Browse Source

generic lib-ot

appflowy 3 years ago
parent
commit
2f413a8e67
44 changed files with 1022 additions and 585 deletions
  1. 6 6
      backend/src/services/doc/edit/editor.rs
  2. 0 1
      backend/src/services/user/auth.rs
  3. 3 3
      backend/tests/document/edit.rs
  4. 5 5
      backend/tests/document/helper.rs
  5. 9 9
      frontend/rust-lib/flowy-document/src/services/doc/edit/editor.rs
  6. 12 12
      frontend/rust-lib/flowy-document/src/services/doc/edit/queue.rs
  7. 4 4
      frontend/rust-lib/flowy-document/src/services/doc/revision/manager.rs
  8. 5 5
      frontend/rust-lib/flowy-document/src/services/doc/revision/persistence.rs
  9. 6 6
      frontend/rust-lib/flowy-document/tests/editor/attribute_test.rs
  10. 18 18
      frontend/rust-lib/flowy-document/tests/editor/mod.rs
  11. 67 64
      frontend/rust-lib/flowy-document/tests/editor/op_test.rs
  12. 16 16
      frontend/rust-lib/flowy-document/tests/editor/serde_test.rs
  13. 17 17
      shared-lib/flowy-document-infra/src/core/document.rs
  14. 2 2
      shared-lib/flowy-document-infra/src/core/extensions/delete/default_delete.rs
  15. 12 3
      shared-lib/flowy-document-infra/src/core/extensions/delete/preserve_line_format_merge.rs
  16. 7 3
      shared-lib/flowy-document-infra/src/core/extensions/format/helper.rs
  17. 10 2
      shared-lib/flowy-document-infra/src/core/extensions/format/resolve_block_format.rs
  18. 2 2
      shared-lib/flowy-document-infra/src/core/extensions/format/resolve_inline_format.rs
  19. 10 3
      shared-lib/flowy-document-infra/src/core/extensions/insert/auto_exit_block.rs
  20. 12 4
      shared-lib/flowy-document-infra/src/core/extensions/insert/auto_format.rs
  21. 13 5
      shared-lib/flowy-document-infra/src/core/extensions/insert/default_insert.rs
  22. 7 3
      shared-lib/flowy-document-infra/src/core/extensions/insert/mod.rs
  23. 8 8
      shared-lib/flowy-document-infra/src/core/extensions/insert/preserve_block_format.rs
  24. 13 5
      shared-lib/flowy-document-infra/src/core/extensions/insert/preserve_inline_format.rs
  25. 13 5
      shared-lib/flowy-document-infra/src/core/extensions/insert/reset_format_on_new_line.rs
  26. 4 4
      shared-lib/flowy-document-infra/src/core/extensions/mod.rs
  27. 8 8
      shared-lib/flowy-document-infra/src/core/history.rs
  28. 14 4
      shared-lib/flowy-document-infra/src/core/view.rs
  29. 4 4
      shared-lib/flowy-document-infra/src/entities/doc/doc.rs
  30. 2 2
      shared-lib/flowy-document-infra/src/entities/doc/revision.rs
  31. 4 4
      shared-lib/flowy-document-infra/src/user_default.rs
  32. 46 46
      shared-lib/lib-ot/src/core/attributes/attribute.rs
  33. 59 41
      shared-lib/lib-ot/src/core/attributes/attributes.rs
  34. 48 44
      shared-lib/lib-ot/src/core/attributes/attributes_serde.rs
  35. 5 5
      shared-lib/lib-ot/src/core/attributes/builder.rs
  36. 4 4
      shared-lib/lib-ot/src/core/attributes/macros.rs
  37. 17 11
      shared-lib/lib-ot/src/core/delta/builder.rs
  38. 22 16
      shared-lib/lib-ot/src/core/delta/cursor.rs
  39. 99 64
      shared-lib/lib-ot/src/core/delta/delta.rs
  40. 19 9
      shared-lib/lib-ot/src/core/delta/delta_serde.rs
  41. 51 33
      shared-lib/lib-ot/src/core/delta/iterator.rs
  42. 17 12
      shared-lib/lib-ot/src/core/operation/builder.rs
  43. 96 49
      shared-lib/lib-ot/src/core/operation/operation.rs
  44. 226 14
      shared-lib/lib-ot/src/core/operation/operation_serde.rs

+ 6 - 6
backend/src/services/doc/edit/editor.rs

@@ -13,7 +13,7 @@ use flowy_document_infra::{
     entities::ws::{WsDataType, WsDocumentData},
     entities::ws::{WsDataType, WsDocumentData},
     protobuf::{Doc, RevId, RevType, Revision, RevisionRange, UpdateDocParams},
     protobuf::{Doc, RevId, RevType, Revision, RevisionRange, UpdateDocParams},
 };
 };
-use lib_ot::core::{Delta, OperationTransformable};
+use lib_ot::core::{OperationTransformable, RichTextDelta};
 use parking_lot::RwLock;
 use parking_lot::RwLock;
 use protobuf::Message;
 use protobuf::Message;
 use sqlx::PgPool;
 use sqlx::PgPool;
@@ -35,7 +35,7 @@ pub struct ServerDocEditor {
 
 
 impl ServerDocEditor {
 impl ServerDocEditor {
     pub fn new(doc: Doc) -> Result<Self, ServerError> {
     pub fn new(doc: Doc) -> Result<Self, ServerError> {
-        let delta = Delta::from_bytes(&doc.data).map_err(internal_error)?;
+        let delta = RichTextDelta::from_bytes(&doc.data).map_err(internal_error)?;
         let document = Arc::new(RwLock::new(Document::from_delta(delta)));
         let document = Arc::new(RwLock::new(Document::from_delta(delta)));
         let users = DashMap::new();
         let users = DashMap::new();
         Ok(Self {
         Ok(Self {
@@ -123,7 +123,7 @@ impl ServerDocEditor {
     pub fn document_json(&self) -> String { self.document.read().to_json() }
     pub fn document_json(&self) -> String { self.document.read().to_json() }
 
 
     async fn compose_revision(&self, revision: &Revision, pg_pool: Data<PgPool>) -> Result<(), ServerError> {
     async fn compose_revision(&self, revision: &Revision, pg_pool: Data<PgPool>) -> Result<(), ServerError> {
-        let delta = Delta::from_bytes(&revision.delta_data).map_err(internal_error)?;
+        let delta = RichTextDelta::from_bytes(&revision.delta_data).map_err(internal_error)?;
         let _ = self.compose_delta(delta)?;
         let _ = self.compose_delta(delta)?;
         let _ = self.rev_id.fetch_update(SeqCst, SeqCst, |_e| Some(revision.rev_id));
         let _ = self.rev_id.fetch_update(SeqCst, SeqCst, |_e| Some(revision.rev_id));
         let _ = self.save_revision(&revision, pg_pool).await?;
         let _ = self.save_revision(&revision, pg_pool).await?;
@@ -132,7 +132,7 @@ impl ServerDocEditor {
 
 
     #[tracing::instrument(level = "debug", skip(self, revision))]
     #[tracing::instrument(level = "debug", skip(self, revision))]
     fn transform_revision(&self, revision: &Revision) -> Result<Revision, ServerError> {
     fn transform_revision(&self, revision: &Revision) -> Result<Revision, ServerError> {
-        let cli_delta = Delta::from_bytes(&revision.delta_data).map_err(internal_error)?;
+        let cli_delta = RichTextDelta::from_bytes(&revision.delta_data).map_err(internal_error)?;
         let (cli_prime, server_prime) = self
         let (cli_prime, server_prime) = self
             .document
             .document
             .read()
             .read()
@@ -145,7 +145,7 @@ impl ServerDocEditor {
         Ok(cli_revision)
         Ok(cli_revision)
     }
     }
 
 
-    fn mk_revision(&self, base_rev_id: i64, delta: Delta) -> Revision {
+    fn mk_revision(&self, base_rev_id: i64, delta: RichTextDelta) -> Revision {
         let delta_data = delta.to_bytes().to_vec();
         let delta_data = delta.to_bytes().to_vec();
         let md5 = md5(&delta_data);
         let md5 = md5(&delta_data);
         Revision {
         Revision {
@@ -167,7 +167,7 @@ impl ServerDocEditor {
             result,
             result,
         )
         )
     )]
     )]
-    fn compose_delta(&self, delta: Delta) -> Result<(), ServerError> {
+    fn compose_delta(&self, delta: RichTextDelta) -> Result<(), ServerError> {
         if delta.is_empty() {
         if delta.is_empty() {
             log::warn!("Composed delta is empty");
             log::warn!("Composed delta is empty");
         }
         }

+ 0 - 1
backend/src/services/user/auth.rs

@@ -16,7 +16,6 @@ use flowy_user_infra::{
 use sqlx::{PgPool, Postgres};
 use sqlx::{PgPool, Postgres};
 
 
 use super::AUTHORIZED_USERS;
 use super::AUTHORIZED_USERS;
-use crate::services::user::user_default::create_default_workspace;
 
 
 pub async fn sign_in(pool: &PgPool, params: SignInParams) -> Result<SignInResponse, ServerError> {
 pub async fn sign_in(pool: &PgPool, params: SignInParams) -> Result<SignInResponse, ServerError> {
     let email = UserEmail::parse(params.email).map_err(|e| ServerError::params_invalid().context(e))?;
     let email = UserEmail::parse(params.email).map_err(|e| ServerError::params_invalid().context(e))?;

+ 3 - 3
backend/tests/document/edit.rs

@@ -1,6 +1,6 @@
 use crate::document::helper::{DocScript, DocumentTest};
 use crate::document::helper::{DocScript, DocumentTest};
 use flowy_document_infra::core::{Document, FlowyDoc};
 use flowy_document_infra::core::{Document, FlowyDoc};
-use lib_ot::core::{Attribute, Interval};
+use lib_ot::core::{Interval, RichTextAttribute};
 
 
 #[rustfmt::skip]
 #[rustfmt::skip]
 //                         ┌─────────┐       ┌─────────┐
 //                         ┌─────────┐       ┌─────────┐
@@ -51,11 +51,11 @@ async fn delta_sync_while_editing_with_attribute() {
         DocScript::ClientConnectWs,
         DocScript::ClientConnectWs,
         DocScript::ClientOpenDoc,
         DocScript::ClientOpenDoc,
         DocScript::ClientInsertText(0, "abc"),
         DocScript::ClientInsertText(0, "abc"),
-        DocScript::ClientFormatText(Interval::new(0, 3), Attribute::Bold(true)),
+        DocScript::ClientFormatText(Interval::new(0, 3), RichTextAttribute::Bold(true)),
         DocScript::AssertClient(r#"[{"insert":"abc","attributes":{"bold":true}},{"insert":"\n"}]"#),
         DocScript::AssertClient(r#"[{"insert":"abc","attributes":{"bold":true}},{"insert":"\n"}]"#),
         DocScript::AssertServer(r#"[{"insert":"abc","attributes":{"bold":true}},{"insert":"\n"}]"#, 2),
         DocScript::AssertServer(r#"[{"insert":"abc","attributes":{"bold":true}},{"insert":"\n"}]"#, 2),
         DocScript::ClientInsertText(3, "efg"),
         DocScript::ClientInsertText(3, "efg"),
-        DocScript::ClientFormatText(Interval::new(3, 5), Attribute::Italic(true)),
+        DocScript::ClientFormatText(Interval::new(3, 5), RichTextAttribute::Italic(true)),
         DocScript::AssertClient(r#"[{"insert":"abc","attributes":{"bold":true}},{"insert":"ef","attributes":{"bold":true,"italic":true}},{"insert":"g","attributes":{"bold":true}},{"insert":"\n"}]"#),
         DocScript::AssertClient(r#"[{"insert":"abc","attributes":{"bold":true}},{"insert":"ef","attributes":{"bold":true,"italic":true}},{"insert":"g","attributes":{"bold":true}},{"insert":"\n"}]"#),
         DocScript::AssertServer(r#"[{"insert":"abc","attributes":{"bold":true}},{"insert":"ef","attributes":{"bold":true,"italic":true}},{"insert":"g","attributes":{"bold":true}},{"insert":"\n"}]"#, 4),
         DocScript::AssertServer(r#"[{"insert":"abc","attributes":{"bold":true}},{"insert":"ef","attributes":{"bold":true,"italic":true}},{"insert":"g","attributes":{"bold":true}},{"insert":"\n"}]"#, 4),
     ])
     ])

+ 5 - 5
backend/tests/document/helper.rs

@@ -1,7 +1,7 @@
 #![allow(clippy::all)]
 #![allow(clippy::all)]
 #![cfg_attr(rustfmt, rustfmt::skip)]
 #![cfg_attr(rustfmt, rustfmt::skip)]
 use actix_web::web::Data;
 use actix_web::web::Data;
-use backend::service::doc::{crud::update_doc, manager::DocManager};
+use backend::services::doc::{crud::update_doc, manager::DocManager};
 use flowy_document::services::doc::ClientDocEditor as ClientEditDocContext;
 use flowy_document::services::doc::ClientDocEditor as ClientEditDocContext;
 use flowy_test::{workspace::ViewTest, FlowyTest};
 use flowy_test::{workspace::ViewTest, FlowyTest};
 use flowy_user::services::user::UserSession;
 use flowy_user::services::user::UserSession;
@@ -12,7 +12,7 @@ use tokio::time::{sleep, Duration};
 // use crate::helper::*;
 // use crate::helper::*;
 use crate::util::helper::{spawn_server, TestServer};
 use crate::util::helper::{spawn_server, TestServer};
 use flowy_document_infra::{entities::doc::DocIdentifier, protobuf::UpdateDocParams};
 use flowy_document_infra::{entities::doc::DocIdentifier, protobuf::UpdateDocParams};
-use lib_ot::core::{Attribute, Delta, Interval};
+use lib_ot::core::{RichTextAttribute, RichTextDelta, Interval};
 use parking_lot::RwLock;
 use parking_lot::RwLock;
 
 
 pub struct DocumentTest {
 pub struct DocumentTest {
@@ -23,7 +23,7 @@ pub struct DocumentTest {
 pub enum DocScript {
 pub enum DocScript {
     ClientConnectWs,
     ClientConnectWs,
     ClientInsertText(usize, &'static str),
     ClientInsertText(usize, &'static str),
-    ClientFormatText(Interval, Attribute),
+    ClientFormatText(Interval, RichTextAttribute),
     ClientOpenDoc,
     ClientOpenDoc,
     AssertClient(&'static str),
     AssertClient(&'static str),
     AssertServer(&'static str, i64),
     AssertServer(&'static str, i64),
@@ -150,8 +150,8 @@ async fn run_scripts(context: Arc<RwLock<ScriptContext>>, scripts: Vec<DocScript
 }
 }
 
 
 fn assert_eq(expect: &str, receive: &str) {
 fn assert_eq(expect: &str, receive: &str) {
-    let expected_delta: Delta = serde_json::from_str(expect).unwrap();
-    let target_delta: Delta = serde_json::from_str(receive).unwrap();
+    let expected_delta: RichTextDelta = serde_json::from_str(expect).unwrap();
+    let target_delta: RichTextDelta = serde_json::from_str(receive).unwrap();
 
 
     if expected_delta != target_delta {
     if expected_delta != target_delta {
         log::error!("✅ expect: {}", expect,);
         log::error!("✅ expect: {}", expect,);

+ 9 - 9
frontend/rust-lib/flowy-document/src/services/doc/edit/editor.rs

@@ -17,7 +17,7 @@ use flowy_document_infra::{
     errors::DocumentResult,
     errors::DocumentResult,
 };
 };
 use lib_infra::retry::{ExponentialBackoff, Retry};
 use lib_infra::retry::{ExponentialBackoff, Retry};
-use lib_ot::core::{Attribute, Delta, Interval};
+use lib_ot::core::{Interval, RichTextAttribute, RichTextDelta};
 use lib_ws::WsConnectState;
 use lib_ws::WsConnectState;
 use std::{convert::TryFrom, sync::Arc};
 use std::{convert::TryFrom, sync::Arc};
 use tokio::sync::{mpsc, mpsc::UnboundedSender, oneshot};
 use tokio::sync::{mpsc, mpsc::UnboundedSender, oneshot};
@@ -60,7 +60,7 @@ impl ClientDocEditor {
     }
     }
 
 
     pub async fn insert<T: ToString>(&self, index: usize, data: T) -> Result<(), DocError> {
     pub async fn insert<T: ToString>(&self, index: usize, data: T) -> Result<(), DocError> {
-        let (ret, rx) = oneshot::channel::<DocumentResult<Delta>>();
+        let (ret, rx) = oneshot::channel::<DocumentResult<RichTextDelta>>();
         let msg = EditCommand::Insert {
         let msg = EditCommand::Insert {
             index,
             index,
             data: data.to_string(),
             data: data.to_string(),
@@ -73,7 +73,7 @@ impl ClientDocEditor {
     }
     }
 
 
     pub async fn delete(&self, interval: Interval) -> Result<(), DocError> {
     pub async fn delete(&self, interval: Interval) -> Result<(), DocError> {
-        let (ret, rx) = oneshot::channel::<DocumentResult<Delta>>();
+        let (ret, rx) = oneshot::channel::<DocumentResult<RichTextDelta>>();
         let msg = EditCommand::Delete { interval, ret };
         let msg = EditCommand::Delete { interval, ret };
         let _ = self.edit_tx.send(msg);
         let _ = self.edit_tx.send(msg);
         let delta = rx.await.map_err(internal_error)??;
         let delta = rx.await.map_err(internal_error)??;
@@ -81,8 +81,8 @@ impl ClientDocEditor {
         Ok(())
         Ok(())
     }
     }
 
 
-    pub async fn format(&self, interval: Interval, attribute: Attribute) -> Result<(), DocError> {
-        let (ret, rx) = oneshot::channel::<DocumentResult<Delta>>();
+    pub async fn format(&self, interval: Interval, attribute: RichTextAttribute) -> Result<(), DocError> {
+        let (ret, rx) = oneshot::channel::<DocumentResult<RichTextDelta>>();
         let msg = EditCommand::Format {
         let msg = EditCommand::Format {
             interval,
             interval,
             attribute,
             attribute,
@@ -95,7 +95,7 @@ impl ClientDocEditor {
     }
     }
 
 
     pub async fn replace<T: ToString>(&mut self, interval: Interval, data: T) -> Result<(), DocError> {
     pub async fn replace<T: ToString>(&mut self, interval: Interval, data: T) -> Result<(), DocError> {
-        let (ret, rx) = oneshot::channel::<DocumentResult<Delta>>();
+        let (ret, rx) = oneshot::channel::<DocumentResult<RichTextDelta>>();
         let msg = EditCommand::Replace {
         let msg = EditCommand::Replace {
             interval,
             interval,
             data: data.to_string(),
             data: data.to_string(),
@@ -149,7 +149,7 @@ impl ClientDocEditor {
         })
         })
     }
     }
 
 
-    async fn save_local_delta(&self, delta: Delta) -> Result<RevId, DocError> {
+    async fn save_local_delta(&self, delta: RichTextDelta) -> Result<RevId, DocError> {
         let delta_data = delta.to_bytes();
         let delta_data = delta.to_bytes();
         let (base_rev_id, rev_id) = self.rev_manager.next_rev_id();
         let (base_rev_id, rev_id) = self.rev_manager.next_rev_id();
         let delta_data = delta_data.to_vec();
         let delta_data = delta_data.to_vec();
@@ -160,7 +160,7 @@ impl ClientDocEditor {
 
 
     #[tracing::instrument(level = "debug", skip(self, data), err)]
     #[tracing::instrument(level = "debug", skip(self, data), err)]
     pub(crate) async fn composing_local_delta(&self, data: Bytes) -> Result<(), DocError> {
     pub(crate) async fn composing_local_delta(&self, data: Bytes) -> Result<(), DocError> {
-        let delta = Delta::from_bytes(&data)?;
+        let delta = RichTextDelta::from_bytes(&data)?;
         let (ret, rx) = oneshot::channel::<DocumentResult<()>>();
         let (ret, rx) = oneshot::channel::<DocumentResult<()>>();
         let msg = EditCommand::ComposeDelta {
         let msg = EditCommand::ComposeDelta {
             delta: delta.clone(),
             delta: delta.clone(),
@@ -314,7 +314,7 @@ fn spawn_rev_receiver(mut receiver: mpsc::UnboundedReceiver<Revision>, ws: Arc<d
     });
     });
 }
 }
 
 
-fn spawn_edit_queue(doc_id: &str, delta: Delta, _pool: Arc<ConnectionPool>) -> UnboundedSender<EditCommand> {
+fn spawn_edit_queue(doc_id: &str, delta: RichTextDelta, _pool: Arc<ConnectionPool>) -> UnboundedSender<EditCommand> {
     let (sender, receiver) = mpsc::unbounded_channel::<EditCommand>();
     let (sender, receiver) = mpsc::unbounded_channel::<EditCommand>();
     let actor = EditCommandQueue::new(doc_id, delta, receiver);
     let actor = EditCommandQueue::new(doc_id, delta, receiver);
     tokio::spawn(actor.run());
     tokio::spawn(actor.run());

+ 12 - 12
frontend/rust-lib/flowy-document/src/services/doc/edit/queue.rs

@@ -6,7 +6,7 @@ use flowy_document_infra::{
     errors::DocumentError,
     errors::DocumentError,
 };
 };
 use futures::stream::StreamExt;
 use futures::stream::StreamExt;
-use lib_ot::core::{Attribute, Delta, Interval, OperationTransformable};
+use lib_ot::core::{Interval, OperationTransformable, RichTextAttribute, RichTextDelta};
 use std::{convert::TryFrom, sync::Arc};
 use std::{convert::TryFrom, sync::Arc};
 use tokio::sync::{mpsc, oneshot, RwLock};
 use tokio::sync::{mpsc, oneshot, RwLock};
 
 
@@ -17,7 +17,7 @@ pub(crate) struct EditCommandQueue {
 }
 }
 
 
 impl EditCommandQueue {
 impl EditCommandQueue {
-    pub(crate) fn new(doc_id: &str, delta: Delta, receiver: mpsc::UnboundedReceiver<EditCommand>) -> Self {
+    pub(crate) fn new(doc_id: &str, delta: RichTextDelta, receiver: mpsc::UnboundedReceiver<EditCommand>) -> Self {
         let document = Arc::new(RwLock::new(Document::from_delta(delta)));
         let document = Arc::new(RwLock::new(Document::from_delta(delta)));
         Self {
         Self {
             doc_id: doc_id.to_owned(),
             doc_id: doc_id.to_owned(),
@@ -54,7 +54,7 @@ impl EditCommandQueue {
             },
             },
             EditCommand::RemoteRevision { bytes, ret } => {
             EditCommand::RemoteRevision { bytes, ret } => {
                 let revision = Revision::try_from(bytes)?;
                 let revision = Revision::try_from(bytes)?;
-                let delta = Delta::from_bytes(&revision.delta_data)?;
+                let delta = RichTextDelta::from_bytes(&revision.delta_data)?;
                 let rev_id: RevId = revision.rev_id.into();
                 let rev_id: RevId = revision.rev_id.into();
                 let (server_prime, client_prime) = self.document.read().await.delta().transform(&delta)?;
                 let (server_prime, client_prime) = self.document.read().await.delta().transform(&delta)?;
                 let transform_delta = TransformDeltas {
                 let transform_delta = TransformDeltas {
@@ -107,7 +107,7 @@ impl EditCommandQueue {
     }
     }
 
 
     #[tracing::instrument(level = "debug", skip(self, delta), fields(compose_result), err)]
     #[tracing::instrument(level = "debug", skip(self, delta), fields(compose_result), err)]
-    async fn composed_delta(&self, delta: Delta) -> Result<(), DocumentError> {
+    async fn composed_delta(&self, delta: RichTextDelta) -> Result<(), DocumentError> {
         // tracing::debug!("{:?} thread handle_message", thread::current(),);
         // tracing::debug!("{:?} thread handle_message", thread::current(),);
         let mut document = self.document.write().await;
         let mut document = self.document.write().await;
         tracing::Span::current().record(
         tracing::Span::current().record(
@@ -125,7 +125,7 @@ impl EditCommandQueue {
 pub(crate) type Ret<T> = oneshot::Sender<Result<T, DocumentError>>;
 pub(crate) type Ret<T> = oneshot::Sender<Result<T, DocumentError>>;
 pub(crate) enum EditCommand {
 pub(crate) enum EditCommand {
     ComposeDelta {
     ComposeDelta {
-        delta: Delta,
+        delta: RichTextDelta,
         ret: Ret<()>,
         ret: Ret<()>,
     },
     },
     RemoteRevision {
     RemoteRevision {
@@ -135,22 +135,22 @@ pub(crate) enum EditCommand {
     Insert {
     Insert {
         index: usize,
         index: usize,
         data: String,
         data: String,
-        ret: Ret<Delta>,
+        ret: Ret<RichTextDelta>,
     },
     },
     Delete {
     Delete {
         interval: Interval,
         interval: Interval,
-        ret: Ret<Delta>,
+        ret: Ret<RichTextDelta>,
     },
     },
     Format {
     Format {
         interval: Interval,
         interval: Interval,
-        attribute: Attribute,
-        ret: Ret<Delta>,
+        attribute: RichTextAttribute,
+        ret: Ret<RichTextDelta>,
     },
     },
 
 
     Replace {
     Replace {
         interval: Interval,
         interval: Interval,
         data: String,
         data: String,
-        ret: Ret<Delta>,
+        ret: Ret<RichTextDelta>,
     },
     },
     CanUndo {
     CanUndo {
         ret: oneshot::Sender<bool>,
         ret: oneshot::Sender<bool>,
@@ -170,7 +170,7 @@ pub(crate) enum EditCommand {
 }
 }
 
 
 pub(crate) struct TransformDeltas {
 pub(crate) struct TransformDeltas {
-    pub client_prime: Delta,
-    pub server_prime: Delta,
+    pub client_prime: RichTextDelta,
+    pub server_prime: RichTextDelta,
     pub server_rev_id: RevId,
     pub server_rev_id: RevId,
 }
 }

+ 4 - 4
frontend/rust-lib/flowy-document/src/services/doc/revision/manager.rs

@@ -8,7 +8,7 @@ use flowy_document_infra::{
     util::RevIdCounter,
     util::RevIdCounter,
 };
 };
 use lib_infra::future::ResultFuture;
 use lib_infra::future::ResultFuture;
-use lib_ot::core::{Delta, OperationTransformable};
+use lib_ot::core::{OperationTransformable, RichTextDelta};
 use std::sync::Arc;
 use std::sync::Arc;
 use tokio::sync::mpsc;
 use tokio::sync::mpsc;
 
 
@@ -38,7 +38,7 @@ impl RevisionManager {
         }
         }
     }
     }
 
 
-    pub async fn load_document(&mut self) -> DocResult<Delta> {
+    pub async fn load_document(&mut self) -> DocResult<RichTextDelta> {
         let doc = self.rev_store.fetch_document().await?;
         let doc = self.rev_store.fetch_document().await?;
         self.update_rev_id_counter_value(doc.rev_id);
         self.update_rev_id_counter_value(doc.rev_id);
         Ok(doc.delta()?)
         Ok(doc.delta()?)
@@ -67,9 +67,9 @@ impl RevisionManager {
     pub async fn mk_revisions(&self, range: RevisionRange) -> Result<Revision, DocError> {
     pub async fn mk_revisions(&self, range: RevisionRange) -> Result<Revision, DocError> {
         debug_assert!(range.doc_id == self.doc_id);
         debug_assert!(range.doc_id == self.doc_id);
         let revisions = self.rev_store.revs_in_range(range.clone()).await?;
         let revisions = self.rev_store.revs_in_range(range.clone()).await?;
-        let mut new_delta = Delta::new();
+        let mut new_delta = RichTextDelta::new();
         for revision in revisions {
         for revision in revisions {
-            match Delta::from_bytes(revision.delta_data) {
+            match RichTextDelta::from_bytes(revision.delta_data) {
                 Ok(delta) => {
                 Ok(delta) => {
                     new_delta = new_delta.compose(&delta)?;
                     new_delta = new_delta.compose(&delta)?;
                 },
                 },

+ 5 - 5
frontend/rust-lib/flowy-document/src/services/doc/revision/persistence.rs

@@ -9,7 +9,7 @@ use flowy_database::{ConnectionPool, SqliteConnection};
 use flowy_document_infra::entities::doc::{revision_from_doc, Doc, RevId, RevType, Revision, RevisionRange};
 use flowy_document_infra::entities::doc::{revision_from_doc, Doc, RevId, RevType, Revision, RevisionRange};
 use futures::stream::StreamExt;
 use futures::stream::StreamExt;
 use lib_infra::future::ResultFuture;
 use lib_infra::future::ResultFuture;
-use lib_ot::core::{Delta, Operation, OperationTransformable};
+use lib_ot::core::{Operation, OperationTransformable, RichTextDelta};
 use std::{collections::VecDeque, sync::Arc, time::Duration};
 use std::{collections::VecDeque, sync::Arc, time::Duration};
 use tokio::{
 use tokio::{
     sync::{broadcast, mpsc, RwLock},
     sync::{broadcast, mpsc, RwLock},
@@ -188,9 +188,9 @@ async fn fetch_from_local(doc_id: &str, persistence: Arc<Persistence>) -> DocRes
 
 
         let base_rev_id: RevId = revisions.last().unwrap().base_rev_id.into();
         let base_rev_id: RevId = revisions.last().unwrap().base_rev_id.into();
         let rev_id: RevId = revisions.last().unwrap().rev_id.into();
         let rev_id: RevId = revisions.last().unwrap().rev_id.into();
-        let mut delta = Delta::new();
+        let mut delta = RichTextDelta::new();
         for (_, revision) in revisions.into_iter().enumerate() {
         for (_, revision) in revisions.into_iter().enumerate() {
-            match Delta::from_bytes(revision.delta_data) {
+            match RichTextDelta::from_bytes(revision.delta_data) {
                 Ok(local_delta) => {
                 Ok(local_delta) => {
                     delta = delta.compose(&local_delta)?;
                     delta = delta.compose(&local_delta)?;
                 },
                 },
@@ -225,7 +225,7 @@ async fn fetch_from_local(doc_id: &str, persistence: Arc<Persistence>) -> DocRes
 }
 }
 
 
 #[cfg(debug_assertions)]
 #[cfg(debug_assertions)]
-fn validate_delta(doc_id: &str, persistence: Arc<Persistence>, conn: &SqliteConnection, delta: &Delta) {
+fn validate_delta(doc_id: &str, persistence: Arc<Persistence>, conn: &SqliteConnection, delta: &RichTextDelta) {
     if delta.ops.last().is_none() {
     if delta.ops.last().is_none() {
         return;
         return;
     }
     }
@@ -236,7 +236,7 @@ fn validate_delta(doc_id: &str, persistence: Arc<Persistence>, conn: &SqliteConn
         let result = || {
         let result = || {
             let revisions = persistence.rev_sql.read_rev_tables(&doc_id, conn)?;
             let revisions = persistence.rev_sql.read_rev_tables(&doc_id, conn)?;
             for revision in revisions {
             for revision in revisions {
-                let delta = Delta::from_bytes(revision.delta_data)?;
+                let delta = RichTextDelta::from_bytes(revision.delta_data)?;
                 log::error!("Invalid revision: {}:{}", revision.rev_id, delta.to_json());
                 log::error!("Invalid revision: {}:{}", revision.rev_id, delta.to_json());
             }
             }
             Ok::<(), DocError>(())
             Ok::<(), DocError>(())

+ 6 - 6
frontend/rust-lib/flowy-document/tests/editor/attribute_test.rs

@@ -1,7 +1,7 @@
 #![cfg_attr(rustfmt, rustfmt::skip)]
 #![cfg_attr(rustfmt, rustfmt::skip)]
 use crate::editor::{TestBuilder, TestOp::*};
 use crate::editor::{TestBuilder, TestOp::*};
 use flowy_document_infra::core::{FlowyDoc, PlainDoc};
 use flowy_document_infra::core::{FlowyDoc, PlainDoc};
-use lib_ot::core::{Delta, Interval, OperationTransformable, NEW_LINE, WHITESPACE, FlowyStr};
+use lib_ot::core::{Interval, OperationTransformable, NEW_LINE, WHITESPACE, FlowyStr, RichTextDelta};
 use unicode_segmentation::UnicodeSegmentation;
 use unicode_segmentation::UnicodeSegmentation;
 
 
 #[test]
 #[test]
@@ -760,12 +760,12 @@ fn attributes_preserve_list_format_on_merge() {
 
 
 #[test]
 #[test]
 fn delta_compose() {
 fn delta_compose() {
-    let mut delta = Delta::from_json(r#"[{"insert":"\n"}]"#).unwrap();
+    let mut delta = RichTextDelta::from_json(r#"[{"insert":"\n"}]"#).unwrap();
     let deltas = vec![
     let deltas = vec![
-        Delta::from_json(r#"[{"retain":1,"attributes":{"list":"unchecked"}}]"#).unwrap(),
-        Delta::from_json(r#"[{"insert":"a"}]"#).unwrap(),
-        Delta::from_json(r#"[{"retain":1},{"insert":"\n","attributes":{"list":"unchecked"}}]"#).unwrap(),
-        Delta::from_json(r#"[{"retain":2},{"retain":1,"attributes":{"list":""}}]"#).unwrap(),
+        RichTextDelta::from_json(r#"[{"retain":1,"attributes":{"list":"unchecked"}}]"#).unwrap(),
+        RichTextDelta::from_json(r#"[{"insert":"a"}]"#).unwrap(),
+        RichTextDelta::from_json(r#"[{"retain":1},{"insert":"\n","attributes":{"list":"unchecked"}}]"#).unwrap(),
+        RichTextDelta::from_json(r#"[{"retain":2},{"retain":1,"attributes":{"list":""}}]"#).unwrap(),
     ];
     ];
 
 
     for d in deltas {
     for d in deltas {

+ 18 - 18
frontend/rust-lib/flowy-document/tests/editor/mod.rs

@@ -80,8 +80,8 @@ pub enum TestOp {
 
 
 pub struct TestBuilder {
 pub struct TestBuilder {
     documents: Vec<Document>,
     documents: Vec<Document>,
-    deltas: Vec<Option<Delta>>,
-    primes: Vec<Option<Delta>>,
+    deltas: Vec<Option<RichTextDelta>>,
+    primes: Vec<Option<RichTextDelta>>,
 }
 }
 
 
 impl TestBuilder {
 impl TestBuilder {
@@ -125,11 +125,11 @@ impl TestBuilder {
             TestOp::InsertBold(delta_i, s, iv) => {
             TestOp::InsertBold(delta_i, s, iv) => {
                 let document = &mut self.documents[*delta_i];
                 let document = &mut self.documents[*delta_i];
                 document.insert(iv.start, s).unwrap();
                 document.insert(iv.start, s).unwrap();
-                document.format(*iv, Attribute::Bold(true)).unwrap();
+                document.format(*iv, RichTextAttribute::Bold(true)).unwrap();
             },
             },
             TestOp::Bold(delta_i, iv, enable) => {
             TestOp::Bold(delta_i, iv, enable) => {
                 let document = &mut self.documents[*delta_i];
                 let document = &mut self.documents[*delta_i];
-                let attribute = Attribute::Bold(*enable);
+                let attribute = RichTextAttribute::Bold(*enable);
                 let delta = document.format(*iv, attribute).unwrap();
                 let delta = document.format(*iv, attribute).unwrap();
                 tracing::trace!("Bold delta: {}", delta.to_json());
                 tracing::trace!("Bold delta: {}", delta.to_json());
                 self.deltas.insert(*delta_i, Some(delta));
                 self.deltas.insert(*delta_i, Some(delta));
@@ -137,8 +137,8 @@ impl TestBuilder {
             TestOp::Italic(delta_i, iv, enable) => {
             TestOp::Italic(delta_i, iv, enable) => {
                 let document = &mut self.documents[*delta_i];
                 let document = &mut self.documents[*delta_i];
                 let attribute = match *enable {
                 let attribute = match *enable {
-                    true => Attribute::Italic(true),
-                    false => Attribute::Italic(false),
+                    true => RichTextAttribute::Italic(true),
+                    false => RichTextAttribute::Italic(false),
                 };
                 };
                 let delta = document.format(*iv, attribute).unwrap();
                 let delta = document.format(*iv, attribute).unwrap();
                 tracing::trace!("Italic delta: {}", delta.to_json());
                 tracing::trace!("Italic delta: {}", delta.to_json());
@@ -146,21 +146,21 @@ impl TestBuilder {
             },
             },
             TestOp::Header(delta_i, iv, level) => {
             TestOp::Header(delta_i, iv, level) => {
                 let document = &mut self.documents[*delta_i];
                 let document = &mut self.documents[*delta_i];
-                let attribute = Attribute::Header(*level);
+                let attribute = RichTextAttribute::Header(*level);
                 let delta = document.format(*iv, attribute).unwrap();
                 let delta = document.format(*iv, attribute).unwrap();
                 tracing::trace!("Header delta: {}", delta.to_json());
                 tracing::trace!("Header delta: {}", delta.to_json());
                 self.deltas.insert(*delta_i, Some(delta));
                 self.deltas.insert(*delta_i, Some(delta));
             },
             },
             TestOp::Link(delta_i, iv, link) => {
             TestOp::Link(delta_i, iv, link) => {
                 let document = &mut self.documents[*delta_i];
                 let document = &mut self.documents[*delta_i];
-                let attribute = Attribute::Link(link.to_owned());
+                let attribute = RichTextAttribute::Link(link.to_owned());
                 let delta = document.format(*iv, attribute).unwrap();
                 let delta = document.format(*iv, attribute).unwrap();
                 tracing::trace!("Link delta: {}", delta.to_json());
                 tracing::trace!("Link delta: {}", delta.to_json());
                 self.deltas.insert(*delta_i, Some(delta));
                 self.deltas.insert(*delta_i, Some(delta));
             },
             },
             TestOp::Bullet(delta_i, iv, enable) => {
             TestOp::Bullet(delta_i, iv, enable) => {
                 let document = &mut self.documents[*delta_i];
                 let document = &mut self.documents[*delta_i];
-                let attribute = Attribute::Bullet(*enable);
+                let attribute = RichTextAttribute::Bullet(*enable);
                 let delta = document.format(*iv, attribute).unwrap();
                 let delta = document.format(*iv, attribute).unwrap();
                 tracing::debug!("Bullet delta: {}", delta.to_json());
                 tracing::debug!("Bullet delta: {}", delta.to_json());
 
 
@@ -225,8 +225,8 @@ impl TestBuilder {
 
 
             TestOp::AssertDocJson(delta_i, expected) => {
             TestOp::AssertDocJson(delta_i, expected) => {
                 let delta_json = self.documents[*delta_i].to_json();
                 let delta_json = self.documents[*delta_i].to_json();
-                let expected_delta: Delta = serde_json::from_str(expected).unwrap();
-                let target_delta: Delta = serde_json::from_str(&delta_json).unwrap();
+                let expected_delta: RichTextDelta = serde_json::from_str(expected).unwrap();
+                let target_delta: RichTextDelta = serde_json::from_str(&delta_json).unwrap();
 
 
                 if expected_delta != target_delta {
                 if expected_delta != target_delta {
                     log::error!("✅ expect: {}", expected,);
                     log::error!("✅ expect: {}", expected,);
@@ -237,8 +237,8 @@ impl TestBuilder {
 
 
             TestOp::AssertPrimeJson(doc_i, expected) => {
             TestOp::AssertPrimeJson(doc_i, expected) => {
                 let prime_json = self.primes[*doc_i].as_ref().unwrap().to_json();
                 let prime_json = self.primes[*doc_i].as_ref().unwrap().to_json();
-                let expected_prime: Delta = serde_json::from_str(expected).unwrap();
-                let target_prime: Delta = serde_json::from_str(&prime_json).unwrap();
+                let expected_prime: RichTextDelta = serde_json::from_str(expected).unwrap();
+                let target_prime: RichTextDelta = serde_json::from_str(&prime_json).unwrap();
 
 
                 if expected_prime != target_prime {
                 if expected_prime != target_prime {
                     log::error!("✅ expect prime: {}", expected,);
                     log::error!("✅ expect prime: {}", expected,);
@@ -292,8 +292,8 @@ impl Rng {
             .collect()
             .collect()
     }
     }
 
 
-    pub fn gen_delta(&mut self, s: &str) -> Delta {
-        let mut delta = Delta::default();
+    pub fn gen_delta(&mut self, s: &str) -> RichTextDelta {
+        let mut delta = RichTextDelta::default();
         loop {
         loop {
             let left = s.chars().count() - delta.base_len;
             let left = s.chars().count() - delta.base_len;
             if left == 0 {
             if left == 0 {
@@ -306,18 +306,18 @@ impl Rng {
             };
             };
             match self.0.gen_range(0.0, 1.0) {
             match self.0.gen_range(0.0, 1.0) {
                 f if f < 0.2 => {
                 f if f < 0.2 => {
-                    delta.insert(&self.gen_string(i), Attributes::default());
+                    delta.insert(&self.gen_string(i), RichTextAttributes::default());
                 },
                 },
                 f if f < 0.4 => {
                 f if f < 0.4 => {
                     delta.delete(i);
                     delta.delete(i);
                 },
                 },
                 _ => {
                 _ => {
-                    delta.retain(i, Attributes::default());
+                    delta.retain(i, RichTextAttributes::default());
                 },
                 },
             }
             }
         }
         }
         if self.0.gen_range(0.0, 1.0) < 0.3 {
         if self.0.gen_range(0.0, 1.0) < 0.3 {
-            delta.insert(&("1".to_owned() + &self.gen_string(10)), Attributes::default());
+            delta.insert(&("1".to_owned() + &self.gen_string(10)), RichTextAttributes::default());
         }
         }
         delta
         delta
     }
     }

+ 67 - 64
frontend/rust-lib/flowy-document/tests/editor/op_test.rs

@@ -35,7 +35,7 @@ fn attributes_insert_text_at_middle() {
 
 
 #[test]
 #[test]
 fn delta_get_ops_in_interval_1() {
 fn delta_get_ops_in_interval_1() {
-    let mut delta = Delta::default();
+    let mut delta = RichTextDelta::default();
     let insert_a = OpBuilder::insert("123").build();
     let insert_a = OpBuilder::insert("123").build();
     let insert_b = OpBuilder::insert("4").build();
     let insert_b = OpBuilder::insert("4").build();
 
 
@@ -48,7 +48,7 @@ fn delta_get_ops_in_interval_1() {
 
 
 #[test]
 #[test]
 fn delta_get_ops_in_interval_2() {
 fn delta_get_ops_in_interval_2() {
-    let mut delta = Delta::default();
+    let mut delta = RichTextDelta::default();
     let insert_a = OpBuilder::insert("123").build();
     let insert_a = OpBuilder::insert("123").build();
     let insert_b = OpBuilder::insert("4").build();
     let insert_b = OpBuilder::insert("4").build();
     let insert_c = OpBuilder::insert("5").build();
     let insert_c = OpBuilder::insert("5").build();
@@ -92,7 +92,7 @@ fn delta_get_ops_in_interval_2() {
 
 
 #[test]
 #[test]
 fn delta_get_ops_in_interval_3() {
 fn delta_get_ops_in_interval_3() {
-    let mut delta = Delta::default();
+    let mut delta = RichTextDelta::default();
     let insert_a = OpBuilder::insert("123456").build();
     let insert_a = OpBuilder::insert("123456").build();
     delta.add(insert_a.clone());
     delta.add(insert_a.clone());
     assert_eq!(
     assert_eq!(
@@ -103,7 +103,7 @@ fn delta_get_ops_in_interval_3() {
 
 
 #[test]
 #[test]
 fn delta_get_ops_in_interval_4() {
 fn delta_get_ops_in_interval_4() {
-    let mut delta = Delta::default();
+    let mut delta = RichTextDelta::default();
     let insert_a = OpBuilder::insert("12").build();
     let insert_a = OpBuilder::insert("12").build();
     let insert_b = OpBuilder::insert("34").build();
     let insert_b = OpBuilder::insert("34").build();
     let insert_c = OpBuilder::insert("56").build();
     let insert_c = OpBuilder::insert("56").build();
@@ -133,7 +133,7 @@ fn delta_get_ops_in_interval_4() {
 
 
 #[test]
 #[test]
 fn delta_get_ops_in_interval_5() {
 fn delta_get_ops_in_interval_5() {
-    let mut delta = Delta::default();
+    let mut delta = RichTextDelta::default();
     let insert_a = OpBuilder::insert("123456").build();
     let insert_a = OpBuilder::insert("123456").build();
     let insert_b = OpBuilder::insert("789").build();
     let insert_b = OpBuilder::insert("789").build();
     delta.ops.push(insert_a.clone());
     delta.ops.push(insert_a.clone());
@@ -151,7 +151,7 @@ fn delta_get_ops_in_interval_5() {
 
 
 #[test]
 #[test]
 fn delta_get_ops_in_interval_6() {
 fn delta_get_ops_in_interval_6() {
-    let mut delta = Delta::default();
+    let mut delta = RichTextDelta::default();
     let insert_a = OpBuilder::insert("12345678").build();
     let insert_a = OpBuilder::insert("12345678").build();
     delta.add(insert_a.clone());
     delta.add(insert_a.clone());
     assert_eq!(
     assert_eq!(
@@ -162,7 +162,7 @@ fn delta_get_ops_in_interval_6() {
 
 
 #[test]
 #[test]
 fn delta_get_ops_in_interval_7() {
 fn delta_get_ops_in_interval_7() {
-    let mut delta = Delta::default();
+    let mut delta = RichTextDelta::default();
     let insert_a = OpBuilder::insert("12345").build();
     let insert_a = OpBuilder::insert("12345").build();
     let retain_a = OpBuilder::retain(3).build();
     let retain_a = OpBuilder::retain(3).build();
 
 
@@ -182,7 +182,7 @@ fn delta_get_ops_in_interval_7() {
 
 
 #[test]
 #[test]
 fn delta_seek_1() {
 fn delta_seek_1() {
-    let mut delta = Delta::default();
+    let mut delta = RichTextDelta::default();
     let insert_a = OpBuilder::insert("12345").build();
     let insert_a = OpBuilder::insert("12345").build();
     let retain_a = OpBuilder::retain(3).build();
     let retain_a = OpBuilder::retain(3).build();
     delta.add(insert_a.clone());
     delta.add(insert_a.clone());
@@ -194,7 +194,7 @@ fn delta_seek_1() {
 
 
 #[test]
 #[test]
 fn delta_seek_2() {
 fn delta_seek_2() {
-    let mut delta = Delta::default();
+    let mut delta = RichTextDelta::default();
     delta.add(OpBuilder::insert("12345").build());
     delta.add(OpBuilder::insert("12345").build());
 
 
     let mut iter = DeltaIter::new(&delta);
     let mut iter = DeltaIter::new(&delta);
@@ -203,7 +203,7 @@ fn delta_seek_2() {
 
 
 #[test]
 #[test]
 fn delta_seek_3() {
 fn delta_seek_3() {
-    let mut delta = Delta::default();
+    let mut delta = RichTextDelta::default();
     delta.add(OpBuilder::insert("12345").build());
     delta.add(OpBuilder::insert("12345").build());
 
 
     let mut iter = DeltaIter::new(&delta);
     let mut iter = DeltaIter::new(&delta);
@@ -218,7 +218,7 @@ fn delta_seek_3() {
 
 
 #[test]
 #[test]
 fn delta_seek_4() {
 fn delta_seek_4() {
-    let mut delta = Delta::default();
+    let mut delta = RichTextDelta::default();
     delta.add(OpBuilder::insert("12345").build());
     delta.add(OpBuilder::insert("12345").build());
 
 
     let mut iter = DeltaIter::new(&delta);
     let mut iter = DeltaIter::new(&delta);
@@ -228,10 +228,10 @@ fn delta_seek_4() {
 
 
 #[test]
 #[test]
 fn delta_seek_5() {
 fn delta_seek_5() {
-    let mut delta = Delta::default();
+    let mut delta = RichTextDelta::default();
     let attributes = AttributeBuilder::new()
     let attributes = AttributeBuilder::new()
-        .add_attr(Attribute::Bold(true))
-        .add_attr(Attribute::Italic(true))
+        .add_attr(RichTextAttribute::Bold(true))
+        .add_attr(RichTextAttribute::Italic(true))
         .build();
         .build();
 
 
     delta.add(OpBuilder::insert("1234").attributes(attributes.clone()).build());
     delta.add(OpBuilder::insert("1234").attributes(attributes.clone()).build());
@@ -248,7 +248,7 @@ fn delta_seek_5() {
 
 
 #[test]
 #[test]
 fn delta_next_op_len_test() {
 fn delta_next_op_len_test() {
-    let mut delta = Delta::default();
+    let mut delta = RichTextDelta::default();
     delta.add(OpBuilder::insert("12345").build());
     delta.add(OpBuilder::insert("12345").build());
 
 
     let mut iter = DeltaIter::new(&delta);
     let mut iter = DeltaIter::new(&delta);
@@ -261,7 +261,7 @@ fn delta_next_op_len_test() {
 
 
 #[test]
 #[test]
 fn delta_next_op_len_test2() {
 fn delta_next_op_len_test2() {
-    let mut delta = Delta::default();
+    let mut delta = RichTextDelta::default();
     delta.add(OpBuilder::insert("12345").build());
     delta.add(OpBuilder::insert("12345").build());
     let mut iter = DeltaIter::new(&delta);
     let mut iter = DeltaIter::new(&delta);
 
 
@@ -272,7 +272,7 @@ fn delta_next_op_len_test2() {
 
 
 #[test]
 #[test]
 fn delta_next_op_with_len_zero() {
 fn delta_next_op_with_len_zero() {
-    let mut delta = Delta::default();
+    let mut delta = RichTextDelta::default();
     delta.add(OpBuilder::insert("12345").build());
     delta.add(OpBuilder::insert("12345").build());
     let mut iter = DeltaIter::new(&delta);
     let mut iter = DeltaIter::new(&delta);
     assert_eq!(iter.next_op_with_len(0), None,);
     assert_eq!(iter.next_op_with_len(0), None,);
@@ -281,7 +281,7 @@ fn delta_next_op_with_len_zero() {
 
 
 #[test]
 #[test]
 fn delta_next_op_with_len_cross_op_return_last() {
 fn delta_next_op_with_len_cross_op_return_last() {
-    let mut delta = Delta::default();
+    let mut delta = RichTextDelta::default();
     delta.add(OpBuilder::insert("12345").build());
     delta.add(OpBuilder::insert("12345").build());
     delta.add(OpBuilder::retain(1).build());
     delta.add(OpBuilder::retain(1).build());
     delta.add(OpBuilder::insert("678").build());
     delta.add(OpBuilder::insert("678").build());
@@ -294,16 +294,16 @@ fn delta_next_op_with_len_cross_op_return_last() {
 
 
 #[test]
 #[test]
 fn lengths() {
 fn lengths() {
-    let mut delta = Delta::default();
+    let mut delta = RichTextDelta::default();
     assert_eq!(delta.base_len, 0);
     assert_eq!(delta.base_len, 0);
     assert_eq!(delta.target_len, 0);
     assert_eq!(delta.target_len, 0);
-    delta.retain(5, Attributes::default());
+    delta.retain(5, RichTextAttributes::default());
     assert_eq!(delta.base_len, 5);
     assert_eq!(delta.base_len, 5);
     assert_eq!(delta.target_len, 5);
     assert_eq!(delta.target_len, 5);
-    delta.insert("abc", Attributes::default());
+    delta.insert("abc", RichTextAttributes::default());
     assert_eq!(delta.base_len, 5);
     assert_eq!(delta.base_len, 5);
     assert_eq!(delta.target_len, 8);
     assert_eq!(delta.target_len, 8);
-    delta.retain(2, Attributes::default());
+    delta.retain(2, RichTextAttributes::default());
     assert_eq!(delta.base_len, 7);
     assert_eq!(delta.base_len, 7);
     assert_eq!(delta.target_len, 10);
     assert_eq!(delta.target_len, 10);
     delta.delete(2);
     delta.delete(2);
@@ -312,11 +312,11 @@ fn lengths() {
 }
 }
 #[test]
 #[test]
 fn sequence() {
 fn sequence() {
-    let mut delta = Delta::default();
-    delta.retain(5, Attributes::default());
-    delta.retain(0, Attributes::default());
-    delta.insert("appflowy", Attributes::default());
-    delta.insert("", Attributes::default());
+    let mut delta = RichTextDelta::default();
+    delta.retain(5, RichTextAttributes::default());
+    delta.retain(0, RichTextAttributes::default());
+    delta.insert("appflowy", RichTextAttributes::default());
+    delta.insert("", RichTextAttributes::default());
     delta.delete(3);
     delta.delete(3);
     delta.delete(0);
     delta.delete(0);
     assert_eq!(delta.ops.len(), 3);
     assert_eq!(delta.ops.len(), 3);
@@ -335,12 +335,12 @@ fn apply_1000() {
 #[test]
 #[test]
 fn apply() {
 fn apply() {
     let s = "hello world,".to_owned();
     let s = "hello world,".to_owned();
-    let mut delta_a = Delta::default();
-    delta_a.insert(&s, Attributes::default());
+    let mut delta_a = RichTextDelta::default();
+    delta_a.insert(&s, RichTextAttributes::default());
 
 
-    let mut delta_b = Delta::default();
-    delta_b.retain(s.len(), Attributes::default());
-    delta_b.insert("appflowy", Attributes::default());
+    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.apply("").unwrap();
     let after_b = delta_b.apply(&after_a).unwrap();
     let after_b = delta_b.apply(&after_a).unwrap();
@@ -349,16 +349,16 @@ fn apply() {
 
 
 #[test]
 #[test]
 fn base_len_test() {
 fn base_len_test() {
-    let mut delta_a = Delta::default();
-    delta_a.insert("a", Attributes::default());
-    delta_a.insert("b", Attributes::default());
-    delta_a.insert("c", Attributes::default());
+    let mut delta_a = RichTextDelta::default();
+    delta_a.insert("a", RichTextAttributes::default());
+    delta_a.insert("b", RichTextAttributes::default());
+    delta_a.insert("c", RichTextAttributes::default());
 
 
     let s = "hello world,".to_owned();
     let s = "hello world,".to_owned();
     delta_a.delete(s.len());
     delta_a.delete(s.len());
     let after_a = delta_a.apply(&s).unwrap();
     let after_a = delta_a.apply(&s).unwrap();
 
 
-    delta_a.insert("d", Attributes::default());
+    delta_a.insert("d", RichTextAttributes::default());
     assert_eq!("abc", &after_a);
     assert_eq!("abc", &after_a);
 }
 }
 
 
@@ -377,43 +377,43 @@ fn invert() {
 
 
 #[test]
 #[test]
 fn empty_ops() {
 fn empty_ops() {
-    let mut delta = Delta::default();
-    delta.retain(0, Attributes::default());
-    delta.insert("", Attributes::default());
+    let mut delta = RichTextDelta::default();
+    delta.retain(0, RichTextAttributes::default());
+    delta.insert("", RichTextAttributes::default());
     delta.delete(0);
     delta.delete(0);
     assert_eq!(delta.ops.len(), 0);
     assert_eq!(delta.ops.len(), 0);
 }
 }
 #[test]
 #[test]
 fn eq() {
 fn eq() {
-    let mut delta_a = Delta::default();
+    let mut delta_a = RichTextDelta::default();
     delta_a.delete(1);
     delta_a.delete(1);
-    delta_a.insert("lo", Attributes::default());
-    delta_a.retain(2, Attributes::default());
-    delta_a.retain(3, Attributes::default());
-    let mut delta_b = Delta::default();
+    delta_a.insert("lo", RichTextAttributes::default());
+    delta_a.retain(2, RichTextAttributes::default());
+    delta_a.retain(3, RichTextAttributes::default());
+    let mut delta_b = RichTextDelta::default();
     delta_b.delete(1);
     delta_b.delete(1);
-    delta_b.insert("l", Attributes::default());
-    delta_b.insert("o", Attributes::default());
-    delta_b.retain(5, Attributes::default());
+    delta_b.insert("l", RichTextAttributes::default());
+    delta_b.insert("o", RichTextAttributes::default());
+    delta_b.retain(5, RichTextAttributes::default());
     assert_eq!(delta_a, delta_b);
     assert_eq!(delta_a, delta_b);
     delta_a.delete(1);
     delta_a.delete(1);
-    delta_b.retain(1, Attributes::default());
+    delta_b.retain(1, RichTextAttributes::default());
     assert_ne!(delta_a, delta_b);
     assert_ne!(delta_a, delta_b);
 }
 }
 #[test]
 #[test]
 fn ops_merging() {
 fn ops_merging() {
-    let mut delta = Delta::default();
+    let mut delta = RichTextDelta::default();
     assert_eq!(delta.ops.len(), 0);
     assert_eq!(delta.ops.len(), 0);
-    delta.retain(2, Attributes::default());
+    delta.retain(2, RichTextAttributes::default());
     assert_eq!(delta.ops.len(), 1);
     assert_eq!(delta.ops.len(), 1);
     assert_eq!(delta.ops.last(), Some(&OpBuilder::retain(2).build()));
     assert_eq!(delta.ops.last(), Some(&OpBuilder::retain(2).build()));
-    delta.retain(3, Attributes::default());
+    delta.retain(3, RichTextAttributes::default());
     assert_eq!(delta.ops.len(), 1);
     assert_eq!(delta.ops.len(), 1);
     assert_eq!(delta.ops.last(), Some(&OpBuilder::retain(5).build()));
     assert_eq!(delta.ops.last(), Some(&OpBuilder::retain(5).build()));
-    delta.insert("abc", Attributes::default());
+    delta.insert("abc", RichTextAttributes::default());
     assert_eq!(delta.ops.len(), 2);
     assert_eq!(delta.ops.len(), 2);
     assert_eq!(delta.ops.last(), Some(&OpBuilder::insert("abc").build()));
     assert_eq!(delta.ops.last(), Some(&OpBuilder::insert("abc").build()));
-    delta.insert("xyz", Attributes::default());
+    delta.insert("xyz", RichTextAttributes::default());
     assert_eq!(delta.ops.len(), 2);
     assert_eq!(delta.ops.len(), 2);
     assert_eq!(delta.ops.last(), Some(&OpBuilder::insert("abcxyz").build()));
     assert_eq!(delta.ops.last(), Some(&OpBuilder::insert("abcxyz").build()));
     delta.delete(1);
     delta.delete(1);
@@ -425,13 +425,13 @@ fn ops_merging() {
 }
 }
 #[test]
 #[test]
 fn is_noop() {
 fn is_noop() {
-    let mut delta = Delta::default();
+    let mut delta = RichTextDelta::default();
     assert!(delta.is_noop());
     assert!(delta.is_noop());
-    delta.retain(5, Attributes::default());
+    delta.retain(5, RichTextAttributes::default());
     assert!(delta.is_noop());
     assert!(delta.is_noop());
-    delta.retain(3, Attributes::default());
+    delta.retain(3, RichTextAttributes::default());
     assert!(delta.is_noop());
     assert!(delta.is_noop());
-    delta.insert("lorem", Attributes::default());
+    delta.insert("lorem", RichTextAttributes::default());
     assert!(!delta.is_noop());
     assert!(!delta.is_noop());
 }
 }
 #[test]
 #[test]
@@ -473,15 +473,18 @@ fn transform_random_delta() {
 
 
 #[test]
 #[test]
 fn transform_with_two_delta_test() {
 fn transform_with_two_delta_test() {
-    let mut a = Delta::default();
+    let mut a = RichTextDelta::default();
     let mut a_s = String::new();
     let mut a_s = String::new();
-    a.insert("123", AttributeBuilder::new().add_attr(Attribute::Bold(true)).build());
+    a.insert(
+        "123",
+        AttributeBuilder::new().add_attr(RichTextAttribute::Bold(true)).build(),
+    );
     a_s = a.apply(&a_s).unwrap();
     a_s = a.apply(&a_s).unwrap();
     assert_eq!(&a_s, "123");
     assert_eq!(&a_s, "123");
 
 
-    let mut b = Delta::default();
+    let mut b = RichTextDelta::default();
     let mut b_s = String::new();
     let mut b_s = String::new();
-    b.insert("456", Attributes::default());
+    b.insert("456", RichTextAttributes::default());
     b_s = b.apply(&b_s).unwrap();
     b_s = b.apply(&b_s).unwrap();
     assert_eq!(&b_s, "456");
     assert_eq!(&b_s, "456");
 
 
@@ -569,10 +572,10 @@ fn transform_two_conflict_non_seq_delta() {
 
 
 #[test]
 #[test]
 fn delta_invert_no_attribute_delta() {
 fn delta_invert_no_attribute_delta() {
-    let mut delta = Delta::default();
+    let mut delta = RichTextDelta::default();
     delta.add(OpBuilder::insert("123").build());
     delta.add(OpBuilder::insert("123").build());
 
 
-    let mut change = Delta::default();
+    let mut change = RichTextDelta::default();
     change.add(OpBuilder::retain(3).build());
     change.add(OpBuilder::retain(3).build());
     change.add(OpBuilder::insert("456").build());
     change.add(OpBuilder::insert("456").build());
     let undo = change.invert(&delta);
     let undo = change.invert(&delta);

+ 16 - 16
frontend/rust-lib/flowy-document/tests/editor/serde_test.rs

@@ -4,14 +4,14 @@ use lib_ot::core::*;
 #[test]
 #[test]
 fn operation_insert_serialize_test() {
 fn operation_insert_serialize_test() {
     let attributes = AttributeBuilder::new()
     let attributes = AttributeBuilder::new()
-        .add_attr(Attribute::Bold(true))
-        .add_attr(Attribute::Italic(true))
+        .add_attr(RichTextAttribute::Bold(true))
+        .add_attr(RichTextAttribute::Italic(true))
         .build();
         .build();
     let operation = OpBuilder::insert("123").attributes(attributes).build();
     let operation = OpBuilder::insert("123").attributes(attributes).build();
     let json = serde_json::to_string(&operation).unwrap();
     let json = serde_json::to_string(&operation).unwrap();
     eprintln!("{}", json);
     eprintln!("{}", json);
 
 
-    let insert_op: Operation = serde_json::from_str(&json).unwrap();
+    let insert_op: RichTextOperation = serde_json::from_str(&json).unwrap();
     assert_eq!(insert_op, operation);
     assert_eq!(insert_op, operation);
 }
 }
 
 
@@ -20,23 +20,23 @@ fn operation_retain_serialize_test() {
     let operation = Operation::Retain(12.into());
     let operation = Operation::Retain(12.into());
     let json = serde_json::to_string(&operation).unwrap();
     let json = serde_json::to_string(&operation).unwrap();
     eprintln!("{}", json);
     eprintln!("{}", json);
-    let insert_op: Operation = serde_json::from_str(&json).unwrap();
+    let insert_op: RichTextOperation = serde_json::from_str(&json).unwrap();
     assert_eq!(insert_op, operation);
     assert_eq!(insert_op, operation);
 }
 }
 
 
 #[test]
 #[test]
 fn operation_delete_serialize_test() {
 fn operation_delete_serialize_test() {
-    let operation = Operation::Delete(2);
+    let operation = RichTextOperation::Delete(2);
     let json = serde_json::to_string(&operation).unwrap();
     let json = serde_json::to_string(&operation).unwrap();
-    let insert_op: Operation = serde_json::from_str(&json).unwrap();
+    let insert_op: RichTextOperation = serde_json::from_str(&json).unwrap();
     assert_eq!(insert_op, operation);
     assert_eq!(insert_op, operation);
 }
 }
 
 
 #[test]
 #[test]
 fn attributes_serialize_test() {
 fn attributes_serialize_test() {
     let attributes = AttributeBuilder::new()
     let attributes = AttributeBuilder::new()
-        .add_attr(Attribute::Bold(true))
-        .add_attr(Attribute::Italic(true))
+        .add_attr(RichTextAttribute::Bold(true))
+        .add_attr(RichTextAttribute::Italic(true))
         .build();
         .build();
     let retain = OpBuilder::insert("123").attributes(attributes).build();
     let retain = OpBuilder::insert("123").attributes(attributes).build();
 
 
@@ -49,8 +49,8 @@ fn delta_serialize_multi_attribute_test() {
     let mut delta = Delta::default();
     let mut delta = Delta::default();
 
 
     let attributes = AttributeBuilder::new()
     let attributes = AttributeBuilder::new()
-        .add_attr(Attribute::Bold(true))
-        .add_attr(Attribute::Italic(true))
+        .add_attr(RichTextAttribute::Bold(true))
+        .add_attr(RichTextAttribute::Italic(true))
         .build();
         .build();
     let retain = OpBuilder::insert("123").attributes(attributes).build();
     let retain = OpBuilder::insert("123").attributes(attributes).build();
 
 
@@ -73,7 +73,7 @@ fn delta_deserialize_test() {
         {"retain":2,"attributes":{"italic":"true","bold":"true"}},
         {"retain":2,"attributes":{"italic":"true","bold":"true"}},
         {"retain":2,"attributes":{"italic":true,"bold":true}}
         {"retain":2,"attributes":{"italic":true,"bold":true}}
      ]"#;
      ]"#;
-    let delta = Delta::from_json(json).unwrap();
+    let delta = RichTextDelta::from_json(json).unwrap();
     eprintln!("{}", delta);
     eprintln!("{}", delta);
 }
 }
 
 
@@ -82,10 +82,10 @@ fn delta_deserialize_null_test() {
     let json = r#"[
     let json = r#"[
         {"retain":7,"attributes":{"bold":null}}
         {"retain":7,"attributes":{"bold":null}}
      ]"#;
      ]"#;
-    let delta1 = Delta::from_json(json).unwrap();
+    let delta1 = RichTextDelta::from_json(json).unwrap();
 
 
-    let mut attribute = Attribute::Bold(true);
-    attribute.value = AttributeValue(None);
+    let mut attribute = RichTextAttribute::Bold(true);
+    attribute.value = RichTextAttributeValue(None);
     let delta2 = DeltaBuilder::new().retain_with_attributes(7, attribute.into()).build();
     let delta2 = DeltaBuilder::new().retain_with_attributes(7, attribute.into()).build();
 
 
     assert_eq!(delta2.to_json(), r#"[{"retain":7,"attributes":{"bold":""}}]"#);
     assert_eq!(delta2.to_json(), r#"[{"retain":7,"attributes":{"bold":""}}]"#);
@@ -94,8 +94,8 @@ fn delta_deserialize_null_test() {
 
 
 #[test]
 #[test]
 fn delta_serde_null_test() {
 fn delta_serde_null_test() {
-    let mut attribute = Attribute::Bold(true);
-    attribute.value = AttributeValue(None);
+    let mut attribute = RichTextAttribute::Bold(true);
+    attribute.value = RichTextAttributeValue(None);
     assert_eq!(attribute.to_json(), r#"{"bold":""}"#);
     assert_eq!(attribute.to_json(), r#"{"bold":""}"#);
 }
 }
 
 

+ 17 - 17
shared-lib/flowy-document-infra/src/core/document.rs

@@ -10,21 +10,21 @@ use lib_ot::core::*;
 use tokio::sync::mpsc;
 use tokio::sync::mpsc;
 
 
 pub trait CustomDocument {
 pub trait CustomDocument {
-    fn init_delta() -> Delta;
+    fn init_delta() -> RichTextDelta;
 }
 }
 
 
 pub struct PlainDoc();
 pub struct PlainDoc();
 impl CustomDocument for PlainDoc {
 impl CustomDocument for PlainDoc {
-    fn init_delta() -> Delta { Delta::new() }
+    fn init_delta() -> RichTextDelta { RichTextDelta::new() }
 }
 }
 
 
 pub struct FlowyDoc();
 pub struct FlowyDoc();
 impl CustomDocument for FlowyDoc {
 impl CustomDocument for FlowyDoc {
-    fn init_delta() -> Delta { doc_initial_delta() }
+    fn init_delta() -> RichTextDelta { doc_initial_delta() }
 }
 }
 
 
 pub struct Document {
 pub struct Document {
-    delta: Delta,
+    delta: RichTextDelta,
     history: History,
     history: History,
     view: View,
     view: View,
     last_edit_time: usize,
     last_edit_time: usize,
@@ -34,7 +34,7 @@ pub struct Document {
 impl Document {
 impl Document {
     pub fn new<C: CustomDocument>() -> Self { Self::from_delta(C::init_delta()) }
     pub fn new<C: CustomDocument>() -> Self { Self::from_delta(C::init_delta()) }
 
 
-    pub fn from_delta(delta: Delta) -> Self {
+    pub fn from_delta(delta: RichTextDelta) -> Self {
         Document {
         Document {
             delta,
             delta,
             history: History::new(),
             history: History::new(),
@@ -45,7 +45,7 @@ impl Document {
     }
     }
 
 
     pub fn from_json(json: &str) -> Result<Self, DocumentError> {
     pub fn from_json(json: &str) -> Result<Self, DocumentError> {
-        let delta = Delta::from_json(json)?;
+        let delta = RichTextDelta::from_json(json)?;
         Ok(Self::from_delta(delta))
         Ok(Self::from_delta(delta))
     }
     }
 
 
@@ -55,11 +55,11 @@ impl Document {
 
 
     pub fn to_plain_string(&self) -> String { self.delta.apply("").unwrap() }
     pub fn to_plain_string(&self) -> String { self.delta.apply("").unwrap() }
 
 
-    pub fn delta(&self) -> &Delta { &self.delta }
+    pub fn delta(&self) -> &RichTextDelta { &self.delta }
 
 
     pub fn set_notify(&mut self, notify: mpsc::UnboundedSender<()>) { self.notify = Some(notify); }
     pub fn set_notify(&mut self, notify: mpsc::UnboundedSender<()>) { self.notify = Some(notify); }
 
 
-    pub fn set_delta(&mut self, data: Delta) {
+    pub fn set_delta(&mut self, data: RichTextDelta) {
         self.delta = data;
         self.delta = data;
 
 
         match &self.notify {
         match &self.notify {
@@ -70,7 +70,7 @@ impl Document {
         }
         }
     }
     }
 
 
-    pub fn compose_delta(&mut self, mut delta: Delta) -> Result<(), DocumentError> {
+    pub fn compose_delta(&mut self, mut delta: RichTextDelta) -> Result<(), DocumentError> {
         trim(&mut delta);
         trim(&mut delta);
         tracing::trace!("{} compose {}", &self.delta.to_json(), delta.to_json());
         tracing::trace!("{} compose {}", &self.delta.to_json(), delta.to_json());
         let mut composed_delta = self.delta.compose(&delta)?;
         let mut composed_delta = self.delta.compose(&delta)?;
@@ -100,7 +100,7 @@ impl Document {
         Ok(())
         Ok(())
     }
     }
 
 
-    pub fn insert<T: ToString>(&mut self, index: usize, data: T) -> Result<Delta, DocumentError> {
+    pub fn insert<T: ToString>(&mut self, index: usize, data: T) -> Result<RichTextDelta, DocumentError> {
         let interval = Interval::new(index, index);
         let interval = Interval::new(index, index);
         let _ = validate_interval(&self.delta, &interval)?;
         let _ = validate_interval(&self.delta, &interval)?;
 
 
@@ -111,7 +111,7 @@ impl Document {
         Ok(delta)
         Ok(delta)
     }
     }
 
 
-    pub fn delete(&mut self, interval: Interval) -> Result<Delta, DocumentError> {
+    pub fn delete(&mut self, interval: Interval) -> Result<RichTextDelta, DocumentError> {
         let _ = validate_interval(&self.delta, &interval)?;
         let _ = validate_interval(&self.delta, &interval)?;
         debug_assert_eq!(interval.is_empty(), false);
         debug_assert_eq!(interval.is_empty(), false);
         let delete = self.view.delete(&self.delta, interval)?;
         let delete = self.view.delete(&self.delta, interval)?;
@@ -122,7 +122,7 @@ impl Document {
         Ok(delete)
         Ok(delete)
     }
     }
 
 
-    pub fn format(&mut self, interval: Interval, attribute: Attribute) -> Result<Delta, DocumentError> {
+    pub fn format(&mut self, interval: Interval, attribute: RichTextAttribute) -> Result<RichTextDelta, DocumentError> {
         let _ = validate_interval(&self.delta, &interval)?;
         let _ = validate_interval(&self.delta, &interval)?;
         tracing::trace!("format with {} at {}", attribute, interval);
         tracing::trace!("format with {} at {}", attribute, interval);
         let format_delta = self.view.format(&self.delta, attribute, interval).unwrap();
         let format_delta = self.view.format(&self.delta, attribute, interval).unwrap();
@@ -132,9 +132,9 @@ impl Document {
         Ok(format_delta)
         Ok(format_delta)
     }
     }
 
 
-    pub fn replace<T: ToString>(&mut self, interval: Interval, data: T) -> Result<Delta, DocumentError> {
+    pub fn replace<T: ToString>(&mut self, interval: Interval, data: T) -> Result<RichTextDelta, DocumentError> {
         let _ = validate_interval(&self.delta, &interval)?;
         let _ = validate_interval(&self.delta, &interval)?;
-        let mut delta = Delta::default();
+        let mut delta = RichTextDelta::default();
         let text = data.to_string();
         let text = data.to_string();
         if !text.is_empty() {
         if !text.is_empty() {
             delta = self.view.insert(&self.delta, &text, interval)?;
             delta = self.view.insert(&self.delta, &text, interval)?;
@@ -184,7 +184,7 @@ impl Document {
 }
 }
 
 
 impl Document {
 impl Document {
-    fn invert(&self, delta: &Delta) -> Result<(Delta, Delta), DocumentError> {
+    fn invert(&self, delta: &RichTextDelta) -> Result<(RichTextDelta, RichTextDelta), DocumentError> {
         // c = a.compose(b)
         // c = a.compose(b)
         // d = b.invert(a)
         // d = b.invert(a)
         // a = c.compose(d)
         // a = c.compose(d)
@@ -195,7 +195,7 @@ impl Document {
     }
     }
 }
 }
 
 
-fn validate_interval(delta: &Delta, interval: &Interval) -> Result<(), DocumentError> {
+fn validate_interval(delta: &RichTextDelta, interval: &Interval) -> Result<(), DocumentError> {
     if delta.target_len < interval.end {
     if delta.target_len < interval.end {
         log::error!("{:?} out of bounds. should 0..{}", interval, delta.target_len);
         log::error!("{:?} out of bounds. should 0..{}", interval, delta.target_len);
         return Err(DocumentError::out_of_bound());
         return Err(DocumentError::out_of_bound());
@@ -204,7 +204,7 @@ fn validate_interval(delta: &Delta, interval: &Interval) -> Result<(), DocumentE
 }
 }
 
 
 /// Removes trailing retain operation with empty attributes, if present.
 /// Removes trailing retain operation with empty attributes, if present.
-pub fn trim(delta: &mut Delta) {
+pub fn trim(delta: &mut RichTextDelta) {
     if let Some(last) = delta.ops.last() {
     if let Some(last) = delta.ops.last() {
         if last.is_retain() && last.is_plain() {
         if last.is_retain() && last.is_plain() {
             delta.ops.pop();
             delta.ops.pop();

+ 2 - 2
shared-lib/flowy-document-infra/src/core/extensions/delete/default_delete.rs

@@ -1,11 +1,11 @@
 use crate::core::extensions::DeleteExt;
 use crate::core::extensions::DeleteExt;
-use lib_ot::core::{Delta, DeltaBuilder, Interval};
+use lib_ot::core::{DeltaBuilder, Interval, RichTextDelta};
 
 
 pub struct DefaultDelete {}
 pub struct DefaultDelete {}
 impl DeleteExt for DefaultDelete {
 impl DeleteExt for DefaultDelete {
     fn ext_name(&self) -> &str { "DefaultDelete" }
     fn ext_name(&self) -> &str { "DefaultDelete" }
 
 
-    fn apply(&self, _delta: &Delta, interval: Interval) -> Option<Delta> {
+    fn apply(&self, _delta: &RichTextDelta, interval: Interval) -> Option<RichTextDelta> {
         Some(
         Some(
             DeltaBuilder::new()
             DeltaBuilder::new()
                 .retain(interval.start)
                 .retain(interval.start)

+ 12 - 3
shared-lib/flowy-document-infra/src/core/extensions/delete/preserve_line_format_merge.rs

@@ -1,11 +1,20 @@
 use crate::{core::extensions::DeleteExt, util::is_newline};
 use crate::{core::extensions::DeleteExt, util::is_newline};
-use lib_ot::core::{plain_attributes, CharMetric, Delta, DeltaBuilder, DeltaIter, Interval, NEW_LINE};
+use lib_ot::core::{
+    plain_attributes,
+    Attributes,
+    CharMetric,
+    DeltaBuilder,
+    DeltaIter,
+    Interval,
+    RichTextDelta,
+    NEW_LINE,
+};
 
 
 pub struct PreserveLineFormatOnMerge {}
 pub struct PreserveLineFormatOnMerge {}
 impl DeleteExt for PreserveLineFormatOnMerge {
 impl DeleteExt for PreserveLineFormatOnMerge {
     fn ext_name(&self) -> &str { "PreserveLineFormatOnMerge" }
     fn ext_name(&self) -> &str { "PreserveLineFormatOnMerge" }
 
 
-    fn apply(&self, delta: &Delta, interval: Interval) -> Option<Delta> {
+    fn apply(&self, delta: &RichTextDelta, interval: Interval) -> Option<RichTextDelta> {
         if interval.is_empty() {
         if interval.is_empty() {
             return None;
             return None;
         }
         }
@@ -40,7 +49,7 @@ impl DeleteExt for PreserveLineFormatOnMerge {
                             attributes.mark_all_as_removed_except(None);
                             attributes.mark_all_as_removed_except(None);
 
 
                             if newline_op.has_attribute() {
                             if newline_op.has_attribute() {
-                                attributes.extend(newline_op.get_attributes());
+                                attributes.extend_other(newline_op.get_attributes());
                             }
                             }
 
 
                             new_delta.retain(line_break, plain_attributes());
                             new_delta.retain(line_break, plain_attributes());

+ 7 - 3
shared-lib/flowy-document-infra/src/core/extensions/format/helper.rs

@@ -1,8 +1,12 @@
 use crate::util::find_newline;
 use crate::util::find_newline;
-use lib_ot::core::{plain_attributes, Attribute, AttributeScope, Delta, Operation};
+use lib_ot::core::{plain_attributes, AttributeScope, RichTextAttribute, RichTextDelta, RichTextOperation};
 
 
-pub(crate) fn line_break(op: &Operation, attribute: &Attribute, scope: AttributeScope) -> Delta {
-    let mut new_delta = Delta::new();
+pub(crate) fn line_break(
+    op: &RichTextOperation,
+    attribute: &RichTextAttribute,
+    scope: AttributeScope,
+) -> RichTextDelta {
+    let mut new_delta = RichTextDelta::new();
     let mut start = 0;
     let mut start = 0;
     let end = op.len();
     let end = op.len();
     let mut s = op.get_data();
     let mut s = op.get_data();

+ 10 - 2
shared-lib/flowy-document-infra/src/core/extensions/format/resolve_block_format.rs

@@ -2,13 +2,21 @@ use crate::{
     core::extensions::{format::helper::line_break, FormatExt},
     core::extensions::{format::helper::line_break, FormatExt},
     util::find_newline,
     util::find_newline,
 };
 };
-use lib_ot::core::{plain_attributes, Attribute, AttributeScope, Delta, DeltaBuilder, DeltaIter, Interval};
+use lib_ot::core::{
+    plain_attributes,
+    AttributeScope,
+    DeltaBuilder,
+    DeltaIter,
+    Interval,
+    RichTextAttribute,
+    RichTextDelta,
+};
 
 
 pub struct ResolveBlockFormat {}
 pub struct ResolveBlockFormat {}
 impl FormatExt for ResolveBlockFormat {
 impl FormatExt for ResolveBlockFormat {
     fn ext_name(&self) -> &str { std::any::type_name::<ResolveBlockFormat>() }
     fn ext_name(&self) -> &str { std::any::type_name::<ResolveBlockFormat>() }
 
 
-    fn apply(&self, delta: &Delta, interval: Interval, attribute: &Attribute) -> Option<Delta> {
+    fn apply(&self, delta: &RichTextDelta, interval: Interval, attribute: &RichTextAttribute) -> Option<RichTextDelta> {
         if attribute.scope != AttributeScope::Block {
         if attribute.scope != AttributeScope::Block {
             return None;
             return None;
         }
         }

+ 2 - 2
shared-lib/flowy-document-infra/src/core/extensions/format/resolve_inline_format.rs

@@ -2,13 +2,13 @@ use crate::{
     core::extensions::{format::helper::line_break, FormatExt},
     core::extensions::{format::helper::line_break, FormatExt},
     util::find_newline,
     util::find_newline,
 };
 };
-use lib_ot::core::{Attribute, AttributeScope, Delta, DeltaBuilder, DeltaIter, Interval};
+use lib_ot::core::{AttributeScope, DeltaBuilder, DeltaIter, Interval, RichTextAttribute, RichTextDelta};
 
 
 pub struct ResolveInlineFormat {}
 pub struct ResolveInlineFormat {}
 impl FormatExt for ResolveInlineFormat {
 impl FormatExt for ResolveInlineFormat {
     fn ext_name(&self) -> &str { std::any::type_name::<ResolveInlineFormat>() }
     fn ext_name(&self) -> &str { std::any::type_name::<ResolveInlineFormat>() }
 
 
-    fn apply(&self, delta: &Delta, interval: Interval, attribute: &Attribute) -> Option<Delta> {
+    fn apply(&self, delta: &RichTextDelta, interval: Interval, attribute: &RichTextAttribute) -> Option<RichTextDelta> {
         if attribute.scope != AttributeScope::Inline {
         if attribute.scope != AttributeScope::Inline {
             return None;
             return None;
         }
         }

+ 10 - 3
shared-lib/flowy-document-infra/src/core/extensions/insert/auto_exit_block.rs

@@ -1,12 +1,19 @@
 use crate::{core::extensions::InsertExt, util::is_newline};
 use crate::{core::extensions::InsertExt, util::is_newline};
-use lib_ot::core::{attributes_except_header, is_empty_line_at_index, AttributeKey, Delta, DeltaBuilder, DeltaIter};
+use lib_ot::core::{
+    attributes_except_header,
+    is_empty_line_at_index,
+    DeltaBuilder,
+    DeltaIter,
+    RichTextAttributeKey,
+    RichTextDelta,
+};
 
 
 pub struct AutoExitBlock {}
 pub struct AutoExitBlock {}
 
 
 impl InsertExt for AutoExitBlock {
 impl InsertExt for AutoExitBlock {
     fn ext_name(&self) -> &str { std::any::type_name::<AutoExitBlock>() }
     fn ext_name(&self) -> &str { std::any::type_name::<AutoExitBlock>() }
 
 
-    fn apply(&self, delta: &Delta, replace_len: usize, text: &str, index: usize) -> Option<Delta> {
+    fn apply(&self, delta: &RichTextDelta, replace_len: usize, text: &str, index: usize) -> Option<RichTextDelta> {
         // Auto exit block will be triggered by enter two new lines
         // Auto exit block will be triggered by enter two new lines
         if !is_newline(text) {
         if !is_newline(text) {
             return None;
             return None;
@@ -39,7 +46,7 @@ impl InsertExt for AutoExitBlock {
             },
             },
         }
         }
 
 
-        attributes.mark_all_as_removed_except(Some(AttributeKey::Header));
+        attributes.mark_all_as_removed_except(Some(RichTextAttributeKey::Header));
 
 
         Some(
         Some(
             DeltaBuilder::new()
             DeltaBuilder::new()

+ 12 - 4
shared-lib/flowy-document-infra/src/core/extensions/insert/auto_format.rs

@@ -1,5 +1,13 @@
 use crate::{core::extensions::InsertExt, util::is_whitespace};
 use crate::{core::extensions::InsertExt, util::is_whitespace};
-use lib_ot::core::{count_utf16_code_units, plain_attributes, Attribute, Attributes, Delta, DeltaBuilder, DeltaIter};
+use lib_ot::core::{
+    count_utf16_code_units,
+    plain_attributes,
+    DeltaBuilder,
+    DeltaIter,
+    RichTextAttribute,
+    RichTextAttributes,
+    RichTextDelta,
+};
 use std::cmp::min;
 use std::cmp::min;
 use url::Url;
 use url::Url;
 
 
@@ -7,7 +15,7 @@ pub struct AutoFormatExt {}
 impl InsertExt for AutoFormatExt {
 impl InsertExt for AutoFormatExt {
     fn ext_name(&self) -> &str { std::any::type_name::<AutoFormatExt>() }
     fn ext_name(&self) -> &str { std::any::type_name::<AutoFormatExt>() }
 
 
-    fn apply(&self, delta: &Delta, replace_len: usize, text: &str, index: usize) -> Option<Delta> {
+    fn apply(&self, delta: &RichTextDelta, replace_len: usize, text: &str, index: usize) -> Option<RichTextDelta> {
         // enter whitespace to trigger auto format
         // enter whitespace to trigger auto format
         if !is_whitespace(text) {
         if !is_whitespace(text) {
             return None;
             return None;
@@ -55,9 +63,9 @@ pub enum AutoFormatter {
 }
 }
 
 
 impl AutoFormatter {
 impl AutoFormatter {
-    pub fn to_attributes(&self) -> Attributes {
+    pub fn to_attributes(&self) -> RichTextAttributes {
         match self {
         match self {
-            AutoFormatter::Url(url) => Attribute::Link(url.as_str()).into(),
+            AutoFormatter::Url(url) => RichTextAttribute::Link(url.as_str()).into(),
         }
         }
     }
     }
 
 

+ 13 - 5
shared-lib/flowy-document-infra/src/core/extensions/insert/default_insert.rs

@@ -1,13 +1,21 @@
 use crate::core::extensions::InsertExt;
 use crate::core::extensions::InsertExt;
-use lib_ot::core::{AttributeKey, Attributes, Delta, DeltaBuilder, DeltaIter, NEW_LINE};
+use lib_ot::core::{
+    Attributes,
+    DeltaBuilder,
+    DeltaIter,
+    RichTextAttributeKey,
+    RichTextAttributes,
+    RichTextDelta,
+    NEW_LINE,
+};
 
 
 pub struct DefaultInsertAttribute {}
 pub struct DefaultInsertAttribute {}
 impl InsertExt for DefaultInsertAttribute {
 impl InsertExt for DefaultInsertAttribute {
     fn ext_name(&self) -> &str { std::any::type_name::<DefaultInsertAttribute>() }
     fn ext_name(&self) -> &str { std::any::type_name::<DefaultInsertAttribute>() }
 
 
-    fn apply(&self, delta: &Delta, replace_len: usize, text: &str, index: usize) -> Option<Delta> {
+    fn apply(&self, delta: &RichTextDelta, replace_len: usize, text: &str, index: usize) -> Option<RichTextDelta> {
         let iter = DeltaIter::new(delta);
         let iter = DeltaIter::new(delta);
-        let mut attributes = Attributes::new();
+        let mut attributes = RichTextAttributes::new();
 
 
         // Enable each line split by "\n" remains the block attributes. for example:
         // Enable each line split by "\n" remains the block attributes. for example:
         // insert "\n" to "123456" at index 3
         // insert "\n" to "123456" at index 3
@@ -18,8 +26,8 @@ impl InsertExt for DefaultInsertAttribute {
             match iter.last() {
             match iter.last() {
                 None => {},
                 None => {},
                 Some(op) => {
                 Some(op) => {
-                    if op.get_attributes().contains_key(&AttributeKey::Header) {
-                        attributes.extend(op.get_attributes());
+                    if op.get_attributes().contains_key(&RichTextAttributeKey::Header) {
+                        attributes.extend_other(op.get_attributes());
                     }
                     }
                 },
                 },
             }
             }

+ 7 - 3
shared-lib/flowy-document-infra/src/core/extensions/insert/mod.rs

@@ -2,7 +2,7 @@ use crate::core::extensions::InsertExt;
 pub use auto_exit_block::*;
 pub use auto_exit_block::*;
 pub use auto_format::*;
 pub use auto_format::*;
 pub use default_insert::*;
 pub use default_insert::*;
-use lib_ot::core::Delta;
+use lib_ot::core::RichTextDelta;
 pub use preserve_block_format::*;
 pub use preserve_block_format::*;
 pub use preserve_inline_format::*;
 pub use preserve_inline_format::*;
 pub use reset_format_on_new_line::*;
 pub use reset_format_on_new_line::*;
@@ -18,12 +18,16 @@ pub struct InsertEmbedsExt {}
 impl InsertExt for InsertEmbedsExt {
 impl InsertExt for InsertEmbedsExt {
     fn ext_name(&self) -> &str { "InsertEmbedsExt" }
     fn ext_name(&self) -> &str { "InsertEmbedsExt" }
 
 
-    fn apply(&self, _delta: &Delta, _replace_len: usize, _text: &str, _index: usize) -> Option<Delta> { None }
+    fn apply(&self, _delta: &RichTextDelta, _replace_len: usize, _text: &str, _index: usize) -> Option<RichTextDelta> {
+        None
+    }
 }
 }
 
 
 pub struct ForceNewlineForInsertsAroundEmbedExt {}
 pub struct ForceNewlineForInsertsAroundEmbedExt {}
 impl InsertExt for ForceNewlineForInsertsAroundEmbedExt {
 impl InsertExt for ForceNewlineForInsertsAroundEmbedExt {
     fn ext_name(&self) -> &str { "ForceNewlineForInsertsAroundEmbedExt" }
     fn ext_name(&self) -> &str { "ForceNewlineForInsertsAroundEmbedExt" }
 
 
-    fn apply(&self, _delta: &Delta, _replace_len: usize, _text: &str, _index: usize) -> Option<Delta> { None }
+    fn apply(&self, _delta: &RichTextDelta, _replace_len: usize, _text: &str, _index: usize) -> Option<RichTextDelta> {
+        None
+    }
 }
 }

+ 8 - 8
shared-lib/flowy-document-infra/src/core/extensions/insert/preserve_block_format.rs

@@ -2,12 +2,12 @@ use crate::{core::extensions::InsertExt, util::is_newline};
 use lib_ot::core::{
 use lib_ot::core::{
     attributes_except_header,
     attributes_except_header,
     plain_attributes,
     plain_attributes,
-    Attribute,
-    AttributeKey,
-    Attributes,
-    Delta,
     DeltaBuilder,
     DeltaBuilder,
     DeltaIter,
     DeltaIter,
+    RichTextAttribute,
+    RichTextAttributeKey,
+    RichTextAttributes,
+    RichTextDelta,
     NEW_LINE,
     NEW_LINE,
 };
 };
 
 
@@ -15,7 +15,7 @@ pub struct PreserveBlockFormatOnInsert {}
 impl InsertExt for PreserveBlockFormatOnInsert {
 impl InsertExt for PreserveBlockFormatOnInsert {
     fn ext_name(&self) -> &str { std::any::type_name::<PreserveBlockFormatOnInsert>() }
     fn ext_name(&self) -> &str { std::any::type_name::<PreserveBlockFormatOnInsert>() }
 
 
-    fn apply(&self, delta: &Delta, replace_len: usize, text: &str, index: usize) -> Option<Delta> {
+    fn apply(&self, delta: &RichTextDelta, replace_len: usize, text: &str, index: usize) -> Option<RichTextDelta> {
         if !is_newline(text) {
         if !is_newline(text) {
             return None;
             return None;
         }
         }
@@ -30,9 +30,9 @@ impl InsertExt for PreserveBlockFormatOnInsert {
                     return None;
                     return None;
                 }
                 }
 
 
-                let mut reset_attribute = Attributes::new();
-                if newline_attributes.contains_key(&AttributeKey::Header) {
-                    reset_attribute.add(Attribute::Header(1));
+                let mut reset_attribute = RichTextAttributes::new();
+                if newline_attributes.contains_key(&RichTextAttributeKey::Header) {
+                    reset_attribute.add(RichTextAttribute::Header(1));
                 }
                 }
 
 
                 let lines: Vec<_> = text.split(NEW_LINE).collect();
                 let lines: Vec<_> = text.split(NEW_LINE).collect();

+ 13 - 5
shared-lib/flowy-document-infra/src/core/extensions/insert/preserve_inline_format.rs

@@ -2,13 +2,21 @@ use crate::{
     core::extensions::InsertExt,
     core::extensions::InsertExt,
     util::{contain_newline, is_newline},
     util::{contain_newline, is_newline},
 };
 };
-use lib_ot::core::{plain_attributes, AttributeKey, Delta, DeltaBuilder, DeltaIter, OpNewline, NEW_LINE};
+use lib_ot::core::{
+    plain_attributes,
+    DeltaBuilder,
+    DeltaIter,
+    OpNewline,
+    RichTextAttributeKey,
+    RichTextDelta,
+    NEW_LINE,
+};
 
 
 pub struct PreserveInlineFormat {}
 pub struct PreserveInlineFormat {}
 impl InsertExt for PreserveInlineFormat {
 impl InsertExt for PreserveInlineFormat {
     fn ext_name(&self) -> &str { std::any::type_name::<PreserveInlineFormat>() }
     fn ext_name(&self) -> &str { std::any::type_name::<PreserveInlineFormat>() }
 
 
-    fn apply(&self, delta: &Delta, replace_len: usize, text: &str, index: usize) -> Option<Delta> {
+    fn apply(&self, delta: &RichTextDelta, replace_len: usize, text: &str, index: usize) -> Option<RichTextDelta> {
         if contain_newline(text) {
         if contain_newline(text) {
             return None;
             return None;
         }
         }
@@ -20,7 +28,7 @@ impl InsertExt for PreserveInlineFormat {
         }
         }
 
 
         let mut attributes = prev.get_attributes();
         let mut attributes = prev.get_attributes();
-        if attributes.is_empty() || !attributes.contains_key(&AttributeKey::Link) {
+        if attributes.is_empty() || !attributes.contains_key(&RichTextAttributeKey::Link) {
             return Some(
             return Some(
                 DeltaBuilder::new()
                 DeltaBuilder::new()
                     .retain(index + replace_len)
                     .retain(index + replace_len)
@@ -52,7 +60,7 @@ pub struct PreserveLineFormatOnSplit {}
 impl InsertExt for PreserveLineFormatOnSplit {
 impl InsertExt for PreserveLineFormatOnSplit {
     fn ext_name(&self) -> &str { std::any::type_name::<PreserveLineFormatOnSplit>() }
     fn ext_name(&self) -> &str { std::any::type_name::<PreserveLineFormatOnSplit>() }
 
 
-    fn apply(&self, delta: &Delta, replace_len: usize, text: &str, index: usize) -> Option<Delta> {
+    fn apply(&self, delta: &RichTextDelta, replace_len: usize, text: &str, index: usize) -> Option<RichTextDelta> {
         if !is_newline(text) {
         if !is_newline(text) {
             return None;
             return None;
         }
         }
@@ -69,7 +77,7 @@ impl InsertExt for PreserveLineFormatOnSplit {
             return None;
             return None;
         }
         }
 
 
-        let mut new_delta = Delta::new();
+        let mut new_delta = RichTextDelta::new();
         new_delta.retain(index + replace_len, plain_attributes());
         new_delta.retain(index + replace_len, plain_attributes());
 
 
         if newline_status.is_contain() {
         if newline_status.is_contain() {

+ 13 - 5
shared-lib/flowy-document-infra/src/core/extensions/insert/reset_format_on_new_line.rs

@@ -1,11 +1,19 @@
 use crate::{core::extensions::InsertExt, util::is_newline};
 use crate::{core::extensions::InsertExt, util::is_newline};
-use lib_ot::core::{AttributeKey, Attributes, CharMetric, Delta, DeltaBuilder, DeltaIter, NEW_LINE};
+use lib_ot::core::{
+    CharMetric,
+    DeltaBuilder,
+    DeltaIter,
+    RichTextAttributeKey,
+    RichTextAttributes,
+    RichTextDelta,
+    NEW_LINE,
+};
 
 
 pub struct ResetLineFormatOnNewLine {}
 pub struct ResetLineFormatOnNewLine {}
 impl InsertExt for ResetLineFormatOnNewLine {
 impl InsertExt for ResetLineFormatOnNewLine {
     fn ext_name(&self) -> &str { std::any::type_name::<ResetLineFormatOnNewLine>() }
     fn ext_name(&self) -> &str { std::any::type_name::<ResetLineFormatOnNewLine>() }
 
 
-    fn apply(&self, delta: &Delta, replace_len: usize, text: &str, index: usize) -> Option<Delta> {
+    fn apply(&self, delta: &RichTextDelta, replace_len: usize, text: &str, index: usize) -> Option<RichTextDelta> {
         if !is_newline(text) {
         if !is_newline(text) {
             return None;
             return None;
         }
         }
@@ -17,9 +25,9 @@ impl InsertExt for ResetLineFormatOnNewLine {
             return None;
             return None;
         }
         }
 
 
-        let mut reset_attribute = Attributes::new();
-        if next_op.get_attributes().contains_key(&AttributeKey::Header) {
-            reset_attribute.delete(&AttributeKey::Header);
+        let mut reset_attribute = RichTextAttributes::new();
+        if next_op.get_attributes().contains_key(&RichTextAttributeKey::Header) {
+            reset_attribute.delete(&RichTextAttributeKey::Header);
         }
         }
 
 
         let len = index + replace_len;
         let len = index + replace_len;

+ 4 - 4
shared-lib/flowy-document-infra/src/core/extensions/mod.rs

@@ -2,7 +2,7 @@ pub use delete::*;
 pub use format::*;
 pub use format::*;
 pub use insert::*;
 pub use insert::*;
 
 
-use lib_ot::core::{Attribute, Delta, Interval};
+use lib_ot::core::{Interval, RichTextAttribute, RichTextDelta};
 
 
 mod delete;
 mod delete;
 mod format;
 mod format;
@@ -14,15 +14,15 @@ pub type DeleteExtension = Box<dyn DeleteExt + Send + Sync>;
 
 
 pub trait InsertExt {
 pub trait InsertExt {
     fn ext_name(&self) -> &str;
     fn ext_name(&self) -> &str;
-    fn apply(&self, delta: &Delta, replace_len: usize, text: &str, index: usize) -> Option<Delta>;
+    fn apply(&self, delta: &RichTextDelta, replace_len: usize, text: &str, index: usize) -> Option<RichTextDelta>;
 }
 }
 
 
 pub trait FormatExt {
 pub trait FormatExt {
     fn ext_name(&self) -> &str;
     fn ext_name(&self) -> &str;
-    fn apply(&self, delta: &Delta, interval: Interval, attribute: &Attribute) -> Option<Delta>;
+    fn apply(&self, delta: &RichTextDelta, interval: Interval, attribute: &RichTextAttribute) -> Option<RichTextDelta>;
 }
 }
 
 
 pub trait DeleteExt {
 pub trait DeleteExt {
     fn ext_name(&self) -> &str;
     fn ext_name(&self) -> &str;
-    fn apply(&self, delta: &Delta, interval: Interval) -> Option<Delta>;
+    fn apply(&self, delta: &RichTextDelta, interval: Interval) -> Option<RichTextDelta>;
 }
 }

+ 8 - 8
shared-lib/flowy-document-infra/src/core/history.rs

@@ -1,4 +1,4 @@
-use lib_ot::core::Delta;
+use lib_ot::core::RichTextDelta;
 
 
 const MAX_UNDOS: usize = 20;
 const MAX_UNDOS: usize = 20;
 
 
@@ -21,8 +21,8 @@ impl UndoResult {
 pub struct History {
 pub struct History {
     #[allow(dead_code)]
     #[allow(dead_code)]
     cur_undo: usize,
     cur_undo: usize,
-    undos: Vec<Delta>,
-    redoes: Vec<Delta>,
+    undos: Vec<RichTextDelta>,
+    redoes: Vec<RichTextDelta>,
     capacity: usize,
     capacity: usize,
 }
 }
 
 
@@ -44,11 +44,11 @@ impl History {
 
 
     pub fn can_redo(&self) -> bool { !self.redoes.is_empty() }
     pub fn can_redo(&self) -> bool { !self.redoes.is_empty() }
 
 
-    pub fn add_undo(&mut self, delta: Delta) { self.undos.push(delta); }
+    pub fn add_undo(&mut self, delta: RichTextDelta) { self.undos.push(delta); }
 
 
-    pub fn add_redo(&mut self, delta: Delta) { self.redoes.push(delta); }
+    pub fn add_redo(&mut self, delta: RichTextDelta) { self.redoes.push(delta); }
 
 
-    pub fn record(&mut self, delta: Delta) {
+    pub fn record(&mut self, delta: RichTextDelta) {
         if delta.ops.is_empty() {
         if delta.ops.is_empty() {
             return;
             return;
         }
         }
@@ -61,7 +61,7 @@ impl History {
         }
         }
     }
     }
 
 
-    pub fn undo(&mut self) -> Option<Delta> {
+    pub fn undo(&mut self) -> Option<RichTextDelta> {
         if !self.can_undo() {
         if !self.can_undo() {
             return None;
             return None;
         }
         }
@@ -69,7 +69,7 @@ impl History {
         Some(delta)
         Some(delta)
     }
     }
 
 
-    pub fn redo(&mut self) -> Option<Delta> {
+    pub fn redo(&mut self) -> Option<RichTextDelta> {
         if !self.can_redo() {
         if !self.can_redo() {
             return None;
             return None;
         }
         }

+ 14 - 4
shared-lib/flowy-document-infra/src/core/view.rs

@@ -1,6 +1,6 @@
 use crate::core::extensions::*;
 use crate::core::extensions::*;
 use lib_ot::{
 use lib_ot::{
-    core::{trim, Attribute, Delta, Interval},
+    core::{trim, Interval, RichTextAttribute, RichTextDelta},
     errors::{ErrorBuilder, OTError, OTErrorCode},
     errors::{ErrorBuilder, OTError, OTErrorCode},
 };
 };
 
 
@@ -21,7 +21,12 @@ impl View {
         }
         }
     }
     }
 
 
-    pub(crate) fn insert(&self, delta: &Delta, text: &str, interval: Interval) -> Result<Delta, OTError> {
+    pub(crate) fn insert(
+        &self,
+        delta: &RichTextDelta,
+        text: &str,
+        interval: Interval,
+    ) -> Result<RichTextDelta, OTError> {
         let mut new_delta = None;
         let mut new_delta = None;
         for ext in &self.insert_exts {
         for ext in &self.insert_exts {
             if let Some(mut delta) = ext.apply(delta, interval.size(), text, interval.start) {
             if let Some(mut delta) = ext.apply(delta, interval.size(), text, interval.start) {
@@ -38,7 +43,7 @@ impl View {
         }
         }
     }
     }
 
 
-    pub(crate) fn delete(&self, delta: &Delta, interval: Interval) -> Result<Delta, OTError> {
+    pub(crate) fn delete(&self, delta: &RichTextDelta, interval: Interval) -> Result<RichTextDelta, OTError> {
         let mut new_delta = None;
         let mut new_delta = None;
         for ext in &self.delete_exts {
         for ext in &self.delete_exts {
             if let Some(mut delta) = ext.apply(delta, interval) {
             if let Some(mut delta) = ext.apply(delta, interval) {
@@ -55,7 +60,12 @@ impl View {
         }
         }
     }
     }
 
 
-    pub(crate) fn format(&self, delta: &Delta, attribute: Attribute, interval: Interval) -> Result<Delta, OTError> {
+    pub(crate) fn format(
+        &self,
+        delta: &RichTextDelta,
+        attribute: RichTextAttribute,
+        interval: Interval,
+    ) -> Result<RichTextDelta, OTError> {
         let mut new_delta = None;
         let mut new_delta = None;
         for ext in &self.format_exts {
         for ext in &self.format_exts {
             if let Some(mut delta) = ext.apply(delta, interval, &attribute) {
             if let Some(mut delta) = ext.apply(delta, interval, &attribute) {

+ 4 - 4
shared-lib/flowy-document-infra/src/entities/doc/doc.rs

@@ -1,5 +1,5 @@
 use flowy_derive::ProtoBuf;
 use flowy_derive::ProtoBuf;
-use lib_ot::{core::Delta, errors::OTError};
+use lib_ot::{core::RichTextDelta, errors::OTError};
 
 
 #[derive(ProtoBuf, Default, Debug, Clone)]
 #[derive(ProtoBuf, Default, Debug, Clone)]
 pub struct CreateDocParams {
 pub struct CreateDocParams {
@@ -35,8 +35,8 @@ pub struct Doc {
 }
 }
 
 
 impl Doc {
 impl Doc {
-    pub fn delta(&self) -> Result<Delta, OTError> {
-        let delta = Delta::from_bytes(&self.data)?;
+    pub fn delta(&self) -> Result<RichTextDelta, OTError> {
+        let delta = RichTextDelta::from_bytes(&self.data)?;
         Ok(delta)
         Ok(delta)
     }
     }
 }
 }
@@ -59,7 +59,7 @@ pub struct DocDelta {
     pub doc_id: String,
     pub doc_id: String,
 
 
     #[pb(index = 2)]
     #[pb(index = 2)]
-    pub data: String, // Delta
+    pub data: String, // RichTextDelta
 }
 }
 
 
 #[derive(ProtoBuf, Default, Debug, Clone)]
 #[derive(ProtoBuf, Default, Debug, Clone)]

+ 2 - 2
shared-lib/flowy-document-infra/src/entities/doc/revision.rs

@@ -1,6 +1,6 @@
 use crate::{entities::doc::Doc, util::md5};
 use crate::{entities::doc::Doc, util::md5};
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
-use lib_ot::core::Delta;
+use lib_ot::core::RichTextDelta;
 use std::{fmt::Formatter, ops::RangeInclusive};
 use std::{fmt::Formatter, ops::RangeInclusive};
 
 
 #[derive(Debug, ProtoBuf_Enum, Clone, Eq, PartialEq)]
 #[derive(Debug, ProtoBuf_Enum, Clone, Eq, PartialEq)]
@@ -87,7 +87,7 @@ impl std::fmt::Debug for Revision {
         let _ = f.write_fmt(format_args!("doc_id {}, ", self.doc_id))?;
         let _ = f.write_fmt(format_args!("doc_id {}, ", self.doc_id))?;
         let _ = f.write_fmt(format_args!("base_rev_id {}, ", self.base_rev_id))?;
         let _ = f.write_fmt(format_args!("base_rev_id {}, ", self.base_rev_id))?;
         let _ = f.write_fmt(format_args!("rev_id {}, ", self.rev_id))?;
         let _ = f.write_fmt(format_args!("rev_id {}, ", self.rev_id))?;
-        match Delta::from_bytes(&self.delta_data) {
+        match RichTextDelta::from_bytes(&self.delta_data) {
             Ok(delta) => {
             Ok(delta) => {
                 let _ = f.write_fmt(format_args!("delta {:?}", delta.to_json()))?;
                 let _ = f.write_fmt(format_args!("delta {:?}", delta.to_json()))?;
             },
             },

+ 4 - 4
shared-lib/flowy-document-infra/src/user_default.rs

@@ -1,15 +1,15 @@
-use lib_ot::core::{Delta, DeltaBuilder};
+use lib_ot::core::{DeltaBuilder, RichTextDelta};
 
 
 #[inline]
 #[inline]
-pub fn doc_initial_delta() -> Delta { DeltaBuilder::new().insert("\n").build() }
+pub fn doc_initial_delta() -> RichTextDelta { DeltaBuilder::new().insert("\n").build() }
 
 
 #[inline]
 #[inline]
 pub fn doc_initial_string() -> String { doc_initial_delta().to_json() }
 pub fn doc_initial_string() -> String { doc_initial_delta().to_json() }
 
 
 #[inline]
 #[inline]
-pub fn initial_read_me() -> Delta {
+pub fn initial_read_me() -> RichTextDelta {
     let json = include_str!("READ_ME.json");
     let json = include_str!("READ_ME.json");
-    Delta::from_json(json).unwrap()
+    RichTextDelta::from_json(json).unwrap()
 }
 }
 
 
 #[cfg(test)]
 #[cfg(test)]

+ 46 - 46
shared-lib/lib-ot/src/core/attributes/attribute.rs

@@ -1,19 +1,19 @@
 #![allow(non_snake_case)]
 #![allow(non_snake_case)]
 
 
-use crate::{block_attribute, core::Attributes, ignore_attribute, inline_attribute, list_attribute};
+use crate::{block_attribute, core::RichTextAttributes, ignore_attribute, inline_attribute, list_attribute};
 use lazy_static::lazy_static;
 use lazy_static::lazy_static;
 
 
 use std::{collections::HashSet, fmt, fmt::Formatter, iter::FromIterator};
 use std::{collections::HashSet, fmt, fmt::Formatter, iter::FromIterator};
 use strum_macros::Display;
 use strum_macros::Display;
 
 
 #[derive(Debug, Clone)]
 #[derive(Debug, Clone)]
-pub struct Attribute {
-    pub key: AttributeKey,
-    pub value: AttributeValue,
+pub struct RichTextAttribute {
+    pub key: RichTextAttributeKey,
+    pub value: RichTextAttributeValue,
     pub scope: AttributeScope,
     pub scope: AttributeScope,
 }
 }
 
 
-impl Attribute {
+impl RichTextAttribute {
     // inline
     // inline
     inline_attribute!(Bold, bool);
     inline_attribute!(Bold, bool);
     inline_attribute!(Italic, bool);
     inline_attribute!(Italic, bool);
@@ -55,16 +55,16 @@ impl Attribute {
     }
     }
 }
 }
 
 
-impl fmt::Display for Attribute {
+impl fmt::Display for RichTextAttribute {
     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
         let s = format!("{:?}:{:?} {:?}", self.key, self.value.0, self.scope);
         let s = format!("{:?}:{:?} {:?}", self.key, self.value.0, self.scope);
         f.write_str(&s)
         f.write_str(&s)
     }
     }
 }
 }
 
 
-impl std::convert::From<Attribute> for Attributes {
-    fn from(attr: Attribute) -> Self {
-        let mut attributes = Attributes::new();
+impl std::convert::From<RichTextAttribute> for RichTextAttributes {
+    fn from(attr: RichTextAttribute) -> Self {
+        let mut attributes = RichTextAttributes::new();
         attributes.add(attr);
         attributes.add(attr);
         attributes
         attributes
     }
     }
@@ -73,7 +73,7 @@ impl std::convert::From<Attribute> for Attributes {
 #[derive(Clone, Debug, Display, Hash, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
 #[derive(Clone, Debug, Display, Hash, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
 // serde.rs/variant-attrs.html
 // serde.rs/variant-attrs.html
 // #[serde(rename_all = "snake_case")]
 // #[serde(rename_all = "snake_case")]
-pub enum AttributeKey {
+pub enum RichTextAttributeKey {
     #[serde(rename = "bold")]
     #[serde(rename = "bold")]
     Bold,
     Bold,
     #[serde(rename = "italic")]
     #[serde(rename = "italic")]
@@ -114,80 +114,80 @@ pub enum AttributeKey {
 
 
 // pub trait AttributeValueData<'a>: Serialize + Deserialize<'a> {}
 // pub trait AttributeValueData<'a>: Serialize + Deserialize<'a> {}
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct AttributeValue(pub Option<String>);
+pub struct RichTextAttributeValue(pub Option<String>);
 
 
-impl std::convert::From<&usize> for AttributeValue {
-    fn from(val: &usize) -> Self { AttributeValue::from(*val) }
+impl std::convert::From<&usize> for RichTextAttributeValue {
+    fn from(val: &usize) -> Self { RichTextAttributeValue::from(*val) }
 }
 }
 
 
-impl std::convert::From<usize> for AttributeValue {
+impl std::convert::From<usize> for RichTextAttributeValue {
     fn from(val: usize) -> Self {
     fn from(val: usize) -> Self {
         if val > 0_usize {
         if val > 0_usize {
-            AttributeValue(Some(format!("{}", val)))
+            RichTextAttributeValue(Some(format!("{}", val)))
         } else {
         } else {
-            AttributeValue(None)
+            RichTextAttributeValue(None)
         }
         }
     }
     }
 }
 }
 
 
-impl std::convert::From<&str> for AttributeValue {
+impl std::convert::From<&str> for RichTextAttributeValue {
     fn from(val: &str) -> Self { val.to_owned().into() }
     fn from(val: &str) -> Self { val.to_owned().into() }
 }
 }
 
 
-impl std::convert::From<String> for AttributeValue {
+impl std::convert::From<String> for RichTextAttributeValue {
     fn from(val: String) -> Self {
     fn from(val: String) -> Self {
         if val.is_empty() {
         if val.is_empty() {
-            AttributeValue(None)
+            RichTextAttributeValue(None)
         } else {
         } else {
-            AttributeValue(Some(val))
+            RichTextAttributeValue(Some(val))
         }
         }
     }
     }
 }
 }
 
 
-impl std::convert::From<&bool> for AttributeValue {
-    fn from(val: &bool) -> Self { AttributeValue::from(*val) }
+impl std::convert::From<&bool> for RichTextAttributeValue {
+    fn from(val: &bool) -> Self { RichTextAttributeValue::from(*val) }
 }
 }
 
 
-impl std::convert::From<bool> for AttributeValue {
+impl std::convert::From<bool> for RichTextAttributeValue {
     fn from(val: bool) -> Self {
     fn from(val: bool) -> Self {
         let val = match val {
         let val = match val {
             true => Some("true".to_owned()),
             true => Some("true".to_owned()),
             false => None,
             false => None,
         };
         };
-        AttributeValue(val)
+        RichTextAttributeValue(val)
     }
     }
 }
 }
 
 
-pub fn is_block_except_header(k: &AttributeKey) -> bool {
-    if k == &AttributeKey::Header {
+pub fn is_block_except_header(k: &RichTextAttributeKey) -> bool {
+    if k == &RichTextAttributeKey::Header {
         return false;
         return false;
     }
     }
     BLOCK_KEYS.contains(k)
     BLOCK_KEYS.contains(k)
 }
 }
 
 
 lazy_static! {
 lazy_static! {
-    static ref BLOCK_KEYS: HashSet<AttributeKey> = HashSet::from_iter(vec![
-        AttributeKey::Header,
-        AttributeKey::Indent,
-        AttributeKey::Align,
-        AttributeKey::CodeBlock,
-        AttributeKey::List,
-        AttributeKey::BlockQuote,
+    static ref BLOCK_KEYS: HashSet<RichTextAttributeKey> = HashSet::from_iter(vec![
+        RichTextAttributeKey::Header,
+        RichTextAttributeKey::Indent,
+        RichTextAttributeKey::Align,
+        RichTextAttributeKey::CodeBlock,
+        RichTextAttributeKey::List,
+        RichTextAttributeKey::BlockQuote,
     ]);
     ]);
-    static ref INLINE_KEYS: HashSet<AttributeKey> = HashSet::from_iter(vec![
-        AttributeKey::Bold,
-        AttributeKey::Italic,
-        AttributeKey::Underline,
-        AttributeKey::StrikeThrough,
-        AttributeKey::Link,
-        AttributeKey::Color,
-        AttributeKey::Font,
-        AttributeKey::Size,
-        AttributeKey::Background,
-        AttributeKey::InlineCode,
+    static ref INLINE_KEYS: HashSet<RichTextAttributeKey> = HashSet::from_iter(vec![
+        RichTextAttributeKey::Bold,
+        RichTextAttributeKey::Italic,
+        RichTextAttributeKey::Underline,
+        RichTextAttributeKey::StrikeThrough,
+        RichTextAttributeKey::Link,
+        RichTextAttributeKey::Color,
+        RichTextAttributeKey::Font,
+        RichTextAttributeKey::Size,
+        RichTextAttributeKey::Background,
+        RichTextAttributeKey::InlineCode,
     ]);
     ]);
-    static ref INGORE_KEYS: HashSet<AttributeKey> =
-        HashSet::from_iter(vec![AttributeKey::Width, AttributeKey::Height,]);
+    static ref INGORE_KEYS: HashSet<RichTextAttributeKey> =
+        HashSet::from_iter(vec![RichTextAttributeKey::Width, RichTextAttributeKey::Height,]);
 }
 }
 
 
 #[derive(Debug, PartialEq, Eq, Clone)]
 #[derive(Debug, PartialEq, Eq, Clone)]

+ 59 - 41
shared-lib/lib-ot/src/core/attributes/attributes.rs

@@ -1,15 +1,22 @@
 use crate::{
 use crate::{
-    core::{Attribute, AttributeKey, AttributeValue, Operation, OperationTransformable},
+    core::{
+        Attributes,
+        OperationTransformable,
+        RichTextAttribute,
+        RichTextAttributeKey,
+        RichTextAttributeValue,
+        RichTextOperation,
+    },
     errors::OTError,
     errors::OTError,
 };
 };
 use std::{collections::HashMap, fmt};
 use std::{collections::HashMap, fmt};
 
 
 #[derive(Debug, Clone, Eq, PartialEq)]
 #[derive(Debug, Clone, Eq, PartialEq)]
-pub struct Attributes {
-    pub(crate) inner: HashMap<AttributeKey, AttributeValue>,
+pub struct RichTextAttributes {
+    pub(crate) inner: HashMap<RichTextAttributeKey, RichTextAttributeValue>,
 }
 }
 
 
-impl std::default::Default for Attributes {
+impl std::default::Default for RichTextAttributes {
     fn default() -> Self {
     fn default() -> Self {
         Self {
         Self {
             inner: HashMap::with_capacity(0),
             inner: HashMap::with_capacity(0),
@@ -17,27 +24,31 @@ impl std::default::Default for Attributes {
     }
     }
 }
 }
 
 
-impl fmt::Display for Attributes {
+impl fmt::Display for RichTextAttributes {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_fmt(format_args!("{:?}", self.inner)) }
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_fmt(format_args!("{:?}", self.inner)) }
 }
 }
 
 
-pub fn plain_attributes() -> Attributes { Attributes::default() }
+pub fn plain_attributes() -> RichTextAttributes { RichTextAttributes::default() }
 
 
-impl Attributes {
-    pub fn new() -> Self { Attributes { inner: HashMap::new() } }
+impl RichTextAttributes {
+    pub fn new() -> Self { RichTextAttributes { inner: HashMap::new() } }
 
 
     pub fn is_empty(&self) -> bool { self.inner.is_empty() }
     pub fn is_empty(&self) -> bool { self.inner.is_empty() }
 
 
-    pub fn add(&mut self, attribute: Attribute) {
-        let Attribute { key, value, scope: _ } = attribute;
+    pub fn add(&mut self, attribute: RichTextAttribute) {
+        let RichTextAttribute { key, value, scope: _ } = attribute;
         self.inner.insert(key, value);
         self.inner.insert(key, value);
     }
     }
 
 
-    pub fn add_kv(&mut self, key: AttributeKey, value: AttributeValue) { self.inner.insert(key, value); }
+    pub fn add_kv(&mut self, key: RichTextAttributeKey, value: RichTextAttributeValue) {
+        self.inner.insert(key, value);
+    }
 
 
-    pub fn delete(&mut self, key: &AttributeKey) { self.inner.insert(key.clone(), AttributeValue(None)); }
+    pub fn delete(&mut self, key: &RichTextAttributeKey) {
+        self.inner.insert(key.clone(), RichTextAttributeValue(None));
+    }
 
 
-    pub fn mark_all_as_removed_except(&mut self, attribute: Option<AttributeKey>) {
+    pub fn mark_all_as_removed_except(&mut self, attribute: Option<RichTextAttributeKey>) {
         match attribute {
         match attribute {
             None => {
             None => {
                 self.inner.iter_mut().for_each(|(_k, v)| v.0 = None);
                 self.inner.iter_mut().for_each(|(_k, v)| v.0 = None);
@@ -52,7 +63,7 @@ impl Attributes {
         }
         }
     }
     }
 
 
-    pub fn remove(&mut self, key: AttributeKey) { self.inner.retain(|k, _| k != &key); }
+    pub fn remove(&mut self, key: RichTextAttributeKey) { self.inner.retain(|k, _| k != &key); }
 
 
     // pub fn block_attributes_except_header(attributes: &Attributes) -> Attributes
     // pub fn block_attributes_except_header(attributes: &Attributes) -> Attributes
     // {     let mut new_attributes = Attributes::new();
     // {     let mut new_attributes = Attributes::new();
@@ -65,14 +76,9 @@ impl Attributes {
     //     new_attributes
     //     new_attributes
     // }
     // }
 
 
-    // Remove the empty attribute which value is None.
-    pub fn remove_empty(&mut self) { self.inner.retain(|_, v| v.0.is_some()); }
-
-    pub fn extend(&mut self, other: Attributes) { self.inner.extend(other.inner); }
-
     // Update inner by constructing new attributes from the other if it's
     // Update inner by constructing new attributes from the other if it's
     // not None and replace the key/value with self key/value.
     // not None and replace the key/value with self key/value.
-    pub fn merge(&mut self, other: Option<Attributes>) {
+    pub fn merge(&mut self, other: Option<RichTextAttributes>) {
         if other.is_none() {
         if other.is_none() {
             return;
             return;
         }
         }
@@ -85,13 +91,21 @@ impl Attributes {
     }
     }
 }
 }
 
 
-impl OperationTransformable for Attributes {
+impl Attributes for RichTextAttributes {
+    fn is_empty(&self) -> bool { self.inner.is_empty() }
+
+    fn remove_empty(&mut self) { self.inner.retain(|_, v| v.0.is_some()); }
+
+    fn extend_other(&mut self, other: Self) { self.inner.extend(other.inner); }
+}
+
+impl OperationTransformable for RichTextAttributes {
     fn compose(&self, other: &Self) -> Result<Self, OTError>
     fn compose(&self, other: &Self) -> Result<Self, OTError>
     where
     where
         Self: Sized,
         Self: Sized,
     {
     {
         let mut attributes = self.clone();
         let mut attributes = self.clone();
-        attributes.extend(other.clone());
+        attributes.extend_other(other.clone());
         Ok(attributes)
         Ok(attributes)
     }
     }
 
 
@@ -99,25 +113,29 @@ impl OperationTransformable for Attributes {
     where
     where
         Self: Sized,
         Self: Sized,
     {
     {
-        let a = self.iter().fold(Attributes::new(), |mut new_attributes, (k, v)| {
-            if !other.contains_key(k) {
-                new_attributes.insert(k.clone(), v.clone());
-            }
-            new_attributes
-        });
-
-        let b = other.iter().fold(Attributes::new(), |mut new_attributes, (k, v)| {
-            if !self.contains_key(k) {
-                new_attributes.insert(k.clone(), v.clone());
-            }
-            new_attributes
-        });
+        let a = self
+            .iter()
+            .fold(RichTextAttributes::new(), |mut new_attributes, (k, v)| {
+                if !other.contains_key(k) {
+                    new_attributes.insert(k.clone(), v.clone());
+                }
+                new_attributes
+            });
+
+        let b = other
+            .iter()
+            .fold(RichTextAttributes::new(), |mut new_attributes, (k, v)| {
+                if !self.contains_key(k) {
+                    new_attributes.insert(k.clone(), v.clone());
+                }
+                new_attributes
+            });
 
 
         Ok((a, b))
         Ok((a, b))
     }
     }
 
 
     fn invert(&self, other: &Self) -> Self {
     fn invert(&self, other: &Self) -> Self {
-        let base_inverted = other.iter().fold(Attributes::new(), |mut attributes, (k, v)| {
+        let base_inverted = other.iter().fold(RichTextAttributes::new(), |mut attributes, (k, v)| {
             if other.get(k) != self.get(k) && self.contains_key(k) {
             if other.get(k) != self.get(k) && self.contains_key(k) {
                 attributes.insert(k.clone(), v.clone());
                 attributes.insert(k.clone(), v.clone());
             }
             }
@@ -135,18 +153,18 @@ impl OperationTransformable for Attributes {
     }
     }
 }
 }
 
 
-impl std::ops::Deref for Attributes {
-    type Target = HashMap<AttributeKey, AttributeValue>;
+impl std::ops::Deref for RichTextAttributes {
+    type Target = HashMap<RichTextAttributeKey, RichTextAttributeValue>;
 
 
     fn deref(&self) -> &Self::Target { &self.inner }
     fn deref(&self) -> &Self::Target { &self.inner }
 }
 }
 
 
-impl std::ops::DerefMut for Attributes {
+impl std::ops::DerefMut for RichTextAttributes {
     fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner }
     fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner }
 }
 }
 
 
-pub fn attributes_except_header(op: &Operation) -> Attributes {
+pub fn attributes_except_header(op: &RichTextOperation) -> RichTextAttributes {
     let mut attributes = op.get_attributes();
     let mut attributes = op.get_attributes();
-    attributes.remove(AttributeKey::Header);
+    attributes.remove(RichTextAttributeKey::Header);
     attributes
     attributes
 }
 }

+ 48 - 44
shared-lib/lib-ot/src/core/attributes/attributes_serde.rs

@@ -1,6 +1,6 @@
 #[rustfmt::skip]
 #[rustfmt::skip]
-use crate::core::AttributeValue;
-use crate::core::{Attribute, AttributeKey, Attributes};
+use crate::core::RichTextAttributeValue;
+use crate::core::{RichTextAttribute, RichTextAttributeKey, RichTextAttributes};
 use serde::{
 use serde::{
     de,
     de,
     de::{MapAccess, Visitor},
     de::{MapAccess, Visitor},
@@ -12,7 +12,7 @@ use serde::{
 };
 };
 use std::fmt;
 use std::fmt;
 
 
-impl Serialize for Attribute {
+impl Serialize for RichTextAttribute {
     fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
     fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
     where
     where
         S: Serializer,
         S: Serializer,
@@ -23,7 +23,7 @@ impl Serialize for Attribute {
     }
     }
 }
 }
 
 
-impl Serialize for Attributes {
+impl Serialize for RichTextAttributes {
     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
     where
     where
         S: Serializer,
         S: Serializer,
@@ -40,39 +40,43 @@ impl Serialize for Attributes {
     }
     }
 }
 }
 
 
-fn serial_attribute<S, E>(map_serializer: &mut S, key: &AttributeKey, value: &AttributeValue) -> Result<(), E>
+fn serial_attribute<S, E>(
+    map_serializer: &mut S,
+    key: &RichTextAttributeKey,
+    value: &RichTextAttributeValue,
+) -> Result<(), E>
 where
 where
     S: SerializeMap,
     S: SerializeMap,
     E: From<<S as SerializeMap>::Error>,
     E: From<<S as SerializeMap>::Error>,
 {
 {
     if let Some(v) = &value.0 {
     if let Some(v) = &value.0 {
         match key {
         match key {
-            AttributeKey::Bold
-            | AttributeKey::Italic
-            | AttributeKey::Underline
-            | AttributeKey::StrikeThrough
-            | AttributeKey::CodeBlock
-            | AttributeKey::InlineCode
-            | AttributeKey::BlockQuote => match &v.parse::<bool>() {
+            RichTextAttributeKey::Bold
+            | RichTextAttributeKey::Italic
+            | RichTextAttributeKey::Underline
+            | RichTextAttributeKey::StrikeThrough
+            | RichTextAttributeKey::CodeBlock
+            | RichTextAttributeKey::InlineCode
+            | RichTextAttributeKey::BlockQuote => match &v.parse::<bool>() {
                 Ok(value) => map_serializer.serialize_entry(&key, value)?,
                 Ok(value) => map_serializer.serialize_entry(&key, value)?,
                 Err(e) => log::error!("Serial {:?} failed. {:?}", &key, e),
                 Err(e) => log::error!("Serial {:?} failed. {:?}", &key, e),
             },
             },
 
 
-            AttributeKey::Font
-            | AttributeKey::Size
-            | AttributeKey::Header
-            | AttributeKey::Indent
-            | AttributeKey::Width
-            | AttributeKey::Height => match &v.parse::<i32>() {
+            RichTextAttributeKey::Font
+            | RichTextAttributeKey::Size
+            | RichTextAttributeKey::Header
+            | RichTextAttributeKey::Indent
+            | RichTextAttributeKey::Width
+            | RichTextAttributeKey::Height => match &v.parse::<i32>() {
                 Ok(value) => map_serializer.serialize_entry(&key, value)?,
                 Ok(value) => map_serializer.serialize_entry(&key, value)?,
                 Err(e) => log::error!("Serial {:?} failed. {:?}", &key, e),
                 Err(e) => log::error!("Serial {:?} failed. {:?}", &key, e),
             },
             },
 
 
-            AttributeKey::Link
-            | AttributeKey::Color
-            | AttributeKey::Background
-            | AttributeKey::Align
-            | AttributeKey::List => {
+            RichTextAttributeKey::Link
+            | RichTextAttributeKey::Color
+            | RichTextAttributeKey::Background
+            | RichTextAttributeKey::Align
+            | RichTextAttributeKey::List => {
                 map_serializer.serialize_entry(&key, v)?;
                 map_serializer.serialize_entry(&key, v)?;
             },
             },
         }
         }
@@ -82,23 +86,23 @@ where
     Ok(())
     Ok(())
 }
 }
 
 
-impl<'de> Deserialize<'de> for Attributes {
-    fn deserialize<D>(deserializer: D) -> Result<Attributes, D::Error>
+impl<'de> Deserialize<'de> for RichTextAttributes {
+    fn deserialize<D>(deserializer: D) -> Result<RichTextAttributes, D::Error>
     where
     where
         D: Deserializer<'de>,
         D: Deserializer<'de>,
     {
     {
         struct AttributesVisitor;
         struct AttributesVisitor;
         impl<'de> Visitor<'de> for AttributesVisitor {
         impl<'de> Visitor<'de> for AttributesVisitor {
-            type Value = Attributes;
+            type Value = RichTextAttributes;
             fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("Expect map") }
             fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("Expect map") }
 
 
             fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
             fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
             where
             where
                 A: MapAccess<'de>,
                 A: MapAccess<'de>,
             {
             {
-                let mut attributes = Attributes::new();
-                while let Some(key) = map.next_key::<AttributeKey>()? {
-                    let value = map.next_value::<AttributeValue>()?;
+                let mut attributes = RichTextAttributes::new();
+                while let Some(key) = map.next_key::<RichTextAttributeKey>()? {
+                    let value = map.next_value::<RichTextAttributeValue>()?;
                     attributes.add_kv(key, value);
                     attributes.add_kv(key, value);
                 }
                 }
 
 
@@ -109,7 +113,7 @@ impl<'de> Deserialize<'de> for Attributes {
     }
     }
 }
 }
 
 
-impl Serialize for AttributeValue {
+impl Serialize for RichTextAttributeValue {
     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
     where
     where
         S: Serializer,
         S: Serializer,
@@ -121,14 +125,14 @@ impl Serialize for AttributeValue {
     }
     }
 }
 }
 
 
-impl<'de> Deserialize<'de> for AttributeValue {
-    fn deserialize<D>(deserializer: D) -> Result<AttributeValue, D::Error>
+impl<'de> Deserialize<'de> for RichTextAttributeValue {
+    fn deserialize<D>(deserializer: D) -> Result<RichTextAttributeValue, D::Error>
     where
     where
         D: Deserializer<'de>,
         D: Deserializer<'de>,
     {
     {
         struct AttributeValueVisitor;
         struct AttributeValueVisitor;
         impl<'de> Visitor<'de> for AttributeValueVisitor {
         impl<'de> Visitor<'de> for AttributeValueVisitor {
-            type Value = AttributeValue;
+            type Value = RichTextAttributeValue;
             fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
             fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                 formatter.write_str("bool, usize or string")
                 formatter.write_str("bool, usize or string")
             }
             }
@@ -143,56 +147,56 @@ impl<'de> Deserialize<'de> for AttributeValue {
             where
             where
                 E: de::Error,
                 E: de::Error,
             {
             {
-                Ok(AttributeValue(Some(format!("{}", value))))
+                Ok(RichTextAttributeValue(Some(format!("{}", value))))
             }
             }
 
 
             fn visit_i16<E>(self, value: i16) -> Result<Self::Value, E>
             fn visit_i16<E>(self, value: i16) -> Result<Self::Value, E>
             where
             where
                 E: de::Error,
                 E: de::Error,
             {
             {
-                Ok(AttributeValue(Some(format!("{}", value))))
+                Ok(RichTextAttributeValue(Some(format!("{}", value))))
             }
             }
 
 
             fn visit_i32<E>(self, value: i32) -> Result<Self::Value, E>
             fn visit_i32<E>(self, value: i32) -> Result<Self::Value, E>
             where
             where
                 E: de::Error,
                 E: de::Error,
             {
             {
-                Ok(AttributeValue(Some(format!("{}", value))))
+                Ok(RichTextAttributeValue(Some(format!("{}", value))))
             }
             }
 
 
             fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
             fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
             where
             where
                 E: de::Error,
                 E: de::Error,
             {
             {
-                Ok(AttributeValue(Some(format!("{}", value))))
+                Ok(RichTextAttributeValue(Some(format!("{}", value))))
             }
             }
 
 
             fn visit_u8<E>(self, value: u8) -> Result<Self::Value, E>
             fn visit_u8<E>(self, value: u8) -> Result<Self::Value, E>
             where
             where
                 E: de::Error,
                 E: de::Error,
             {
             {
-                Ok(AttributeValue(Some(format!("{}", value))))
+                Ok(RichTextAttributeValue(Some(format!("{}", value))))
             }
             }
 
 
             fn visit_u16<E>(self, value: u16) -> Result<Self::Value, E>
             fn visit_u16<E>(self, value: u16) -> Result<Self::Value, E>
             where
             where
                 E: de::Error,
                 E: de::Error,
             {
             {
-                Ok(AttributeValue(Some(format!("{}", value))))
+                Ok(RichTextAttributeValue(Some(format!("{}", value))))
             }
             }
 
 
             fn visit_u32<E>(self, value: u32) -> Result<Self::Value, E>
             fn visit_u32<E>(self, value: u32) -> Result<Self::Value, E>
             where
             where
                 E: de::Error,
                 E: de::Error,
             {
             {
-                Ok(AttributeValue(Some(format!("{}", value))))
+                Ok(RichTextAttributeValue(Some(format!("{}", value))))
             }
             }
 
 
             fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
             fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
             where
             where
                 E: de::Error,
                 E: de::Error,
             {
             {
-                Ok(AttributeValue(Some(format!("{}", value))))
+                Ok(RichTextAttributeValue(Some(format!("{}", value))))
             }
             }
 
 
             fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
             fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
@@ -206,7 +210,7 @@ impl<'de> Deserialize<'de> for AttributeValue {
             where
             where
                 E: de::Error,
                 E: de::Error,
             {
             {
-                Ok(AttributeValue(None))
+                Ok(RichTextAttributeValue(None))
             }
             }
 
 
             fn visit_unit<E>(self) -> Result<Self::Value, E>
             fn visit_unit<E>(self) -> Result<Self::Value, E>
@@ -214,7 +218,7 @@ impl<'de> Deserialize<'de> for AttributeValue {
                 E: de::Error,
                 E: de::Error,
             {
             {
                 // the value that contains null will be processed here.
                 // the value that contains null will be processed here.
-                Ok(AttributeValue(None))
+                Ok(RichTextAttributeValue(None))
             }
             }
 
 
             fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
             fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
@@ -223,7 +227,7 @@ impl<'de> Deserialize<'de> for AttributeValue {
             {
             {
                 // https://github.com/serde-rs/json/issues/505
                 // https://github.com/serde-rs/json/issues/505
                 let mut map = map;
                 let mut map = map;
-                let value = map.next_value::<AttributeValue>()?;
+                let value = map.next_value::<RichTextAttributeValue>()?;
                 Ok(value)
                 Ok(value)
             }
             }
         }
         }

+ 5 - 5
shared-lib/lib-ot/src/core/attributes/builder.rs

@@ -1,13 +1,13 @@
 #![allow(non_snake_case)]
 #![allow(non_snake_case)]
-use crate::core::{Attribute, Attributes};
+use crate::core::{RichTextAttribute, RichTextAttributes};
 pub struct AttributeBuilder {
 pub struct AttributeBuilder {
-    inner: Attributes,
+    inner: RichTextAttributes,
 }
 }
 
 
 impl std::default::Default for AttributeBuilder {
 impl std::default::Default for AttributeBuilder {
     fn default() -> Self {
     fn default() -> Self {
         Self {
         Self {
-            inner: Attributes::default(),
+            inner: RichTextAttributes::default(),
         }
         }
     }
     }
 }
 }
@@ -15,10 +15,10 @@ impl std::default::Default for AttributeBuilder {
 impl AttributeBuilder {
 impl AttributeBuilder {
     pub fn new() -> Self { AttributeBuilder::default() }
     pub fn new() -> Self { AttributeBuilder::default() }
 
 
-    pub fn add_attr(mut self, attribute: Attribute) -> Self {
+    pub fn add_attr(mut self, attribute: RichTextAttribute) -> Self {
         self.inner.add(attribute);
         self.inner.add(attribute);
         self
         self
     }
     }
 
 
-    pub fn build(self) -> Attributes { self.inner }
+    pub fn build(self) -> RichTextAttributes { self.inner }
 }
 }

+ 4 - 4
shared-lib/lib-ot/src/core/attributes/macros.rs

@@ -6,7 +6,7 @@ macro_rules! inline_attribute {
     ) => {
     ) => {
         pub fn $key(value: $value) -> Self {
         pub fn $key(value: $value) -> Self {
             Self {
             Self {
-                key: AttributeKey::$key,
+                key: RichTextAttributeKey::$key,
                 value: value.into(),
                 value: value.into(),
                 scope: AttributeScope::Inline,
                 scope: AttributeScope::Inline,
             }
             }
@@ -22,7 +22,7 @@ macro_rules! block_attribute {
     ) => {
     ) => {
         pub fn $key(value: $value) -> Self {
         pub fn $key(value: $value) -> Self {
             Self {
             Self {
-                key: AttributeKey::$key,
+                key: RichTextAttributeKey::$key,
                 value: value.into(),
                 value: value.into(),
                 scope: AttributeScope::Block,
                 scope: AttributeScope::Block,
             }
             }
@@ -41,7 +41,7 @@ macro_rules! list_attribute {
                 true => $value,
                 true => $value,
                 false => "",
                 false => "",
             };
             };
-            Attribute::List(value)
+            RichTextAttribute::List(value)
         }
         }
     };
     };
 }
 }
@@ -54,7 +54,7 @@ macro_rules! ignore_attribute {
     ) => {
     ) => {
         pub fn $key(value: $value) -> Self {
         pub fn $key(value: $value) -> Self {
             Self {
             Self {
-                key: AttributeKey::$key,
+                key: RichTextAttributeKey::$key,
                 value: value.into(),
                 value: value.into(),
                 scope: AttributeScope::Ignore,
                 scope: AttributeScope::Ignore,
             }
             }

+ 17 - 11
shared-lib/lib-ot/src/core/delta/builder.rs

@@ -1,23 +1,29 @@
-use crate::core::{plain_attributes, Attributes, Delta, Operation};
+use crate::core::{Attributes, Delta, Operation};
 
 
-pub struct DeltaBuilder {
-    delta: Delta,
+pub struct DeltaBuilder<T: Attributes> {
+    delta: Delta<T>,
 }
 }
 
 
-impl std::default::Default for DeltaBuilder {
+impl<T> std::default::Default for DeltaBuilder<T>
+where
+    T: Attributes,
+{
     fn default() -> Self { Self { delta: Delta::new() } }
     fn default() -> Self { Self { delta: Delta::new() } }
 }
 }
 
 
-impl DeltaBuilder {
+impl<T> DeltaBuilder<T>
+where
+    T: Attributes,
+{
     pub fn new() -> Self { DeltaBuilder::default() }
     pub fn new() -> Self { DeltaBuilder::default() }
 
 
-    pub fn retain_with_attributes(mut self, n: usize, attrs: Attributes) -> Self {
+    pub fn retain_with_attributes(mut self, n: usize, attrs: T) -> Self {
         self.delta.retain(n, attrs);
         self.delta.retain(n, attrs);
         self
         self
     }
     }
 
 
     pub fn retain(mut self, n: usize) -> Self {
     pub fn retain(mut self, n: usize) -> Self {
-        self.delta.retain(n, plain_attributes());
+        self.delta.retain(n, T::default());
         self
         self
     }
     }
 
 
@@ -26,13 +32,13 @@ impl DeltaBuilder {
         self
         self
     }
     }
 
 
-    pub fn insert_with_attributes(mut self, s: &str, attrs: Attributes) -> Self {
+    pub fn insert_with_attributes(mut self, s: &str, attrs: T) -> Self {
         self.delta.insert(s, attrs);
         self.delta.insert(s, attrs);
         self
         self
     }
     }
 
 
     pub fn insert(mut self, s: &str) -> Self {
     pub fn insert(mut self, s: &str) -> Self {
-        self.delta.insert(s, plain_attributes());
+        self.delta.insert(s, T::default());
         self
         self
     }
     }
 
 
@@ -41,10 +47,10 @@ impl DeltaBuilder {
         self
         self
     }
     }
 
 
-    pub fn build(self) -> Delta { self.delta }
+    pub fn build(self) -> Delta<T> { self.delta }
 }
 }
 
 
-pub fn trim(delta: &mut Delta) {
+pub fn trim<T: Attributes>(delta: &mut Delta<T>) {
     let remove_last = match delta.ops.last() {
     let remove_last = match delta.ops.last() {
         None => false,
         None => false,
         Some(op) => match op {
         Some(op) => match op {

+ 22 - 16
shared-lib/lib-ot/src/core/delta/cursor.rs

@@ -1,22 +1,25 @@
 use crate::{
 use crate::{
-    core::{Delta, Interval, Operation},
+    core::{Attributes, Delta, Interval, Operation},
     errors::{ErrorBuilder, OTError, OTErrorCode},
     errors::{ErrorBuilder, OTError, OTErrorCode},
 };
 };
 use std::{cmp::min, iter::Enumerate, slice::Iter};
 use std::{cmp::min, iter::Enumerate, slice::Iter};
 
 
 #[derive(Debug)]
 #[derive(Debug)]
-pub struct OpCursor<'a> {
-    pub(crate) delta: &'a Delta,
+pub struct OpCursor<'a, T: Attributes> {
+    pub(crate) delta: &'a Delta<T>,
     pub(crate) origin_iv: Interval,
     pub(crate) origin_iv: Interval,
     pub(crate) consume_iv: Interval,
     pub(crate) consume_iv: Interval,
     pub(crate) consume_count: usize,
     pub(crate) consume_count: usize,
     pub(crate) op_index: usize,
     pub(crate) op_index: usize,
-    iter: Enumerate<Iter<'a, Operation>>,
-    next_op: Option<Operation>,
+    iter: Enumerate<Iter<'a, Operation<T>>>,
+    next_op: Option<Operation<T>>,
 }
 }
 
 
-impl<'a> OpCursor<'a> {
-    pub fn new(delta: &'a Delta, interval: Interval) -> OpCursor<'a> {
+impl<'a, T> OpCursor<'a, T>
+where
+    T: Attributes,
+{
+    pub fn new(delta: &'a Delta<T>, interval: Interval) -> OpCursor<'a, T> {
         // debug_assert!(interval.start <= delta.target_len);
         // debug_assert!(interval.start <= delta.target_len);
         let mut cursor = Self {
         let mut cursor = Self {
             delta,
             delta,
@@ -34,11 +37,11 @@ impl<'a> OpCursor<'a> {
     // get the next operation interval
     // get the next operation interval
     pub fn next_iv(&self) -> Interval { self.next_iv_before(None).unwrap_or_else(|| Interval::new(0, 0)) }
     pub fn next_iv(&self) -> Interval { self.next_iv_before(None).unwrap_or_else(|| Interval::new(0, 0)) }
 
 
-    pub fn next_op(&mut self) -> Option<Operation> { self.next_with_len(None) }
+    pub fn next_op(&mut self) -> Option<Operation<T>> { self.next_with_len(None) }
 
 
     // get the last operation before the end.
     // get the last operation before the end.
     // checkout the delta_next_op_with_len_cross_op_return_last test for more detail
     // checkout the delta_next_op_with_len_cross_op_return_last test for more detail
-    pub fn next_with_len(&mut self, force_end: Option<usize>) -> Option<Operation> {
+    pub fn next_with_len(&mut self, force_end: Option<usize>) -> Option<Operation<T>> {
         let mut find_op = None;
         let mut find_op = None;
         let holder = self.next_op.clone();
         let holder = self.next_op.clone();
         let mut next_op = holder.as_ref();
         let mut next_op = holder.as_ref();
@@ -121,7 +124,7 @@ impl<'a> OpCursor<'a> {
         Some(interval)
         Some(interval)
     }
     }
 
 
-    pub fn next_iter_op(&self) -> Option<&Operation> {
+    pub fn next_iter_op(&self) -> Option<&Operation<T>> {
         let mut next_op = self.next_op.as_ref();
         let mut next_op = self.next_op.as_ref();
         if next_op.is_none() {
         if next_op.is_none() {
             let mut offset = 0;
             let mut offset = 0;
@@ -137,7 +140,10 @@ impl<'a> OpCursor<'a> {
     }
     }
 }
 }
 
 
-fn find_next<'a>(cursor: &mut OpCursor<'a>) -> Option<&'a Operation> {
+fn find_next<'a, T>(cursor: &mut OpCursor<'a, T>) -> Option<&'a Operation<T>>
+where
+    T: Attributes,
+{
     match cursor.iter.next() {
     match cursor.iter.next() {
         None => None,
         None => None,
         Some((o_index, op)) => {
         Some((o_index, op)) => {
@@ -149,13 +155,13 @@ fn find_next<'a>(cursor: &mut OpCursor<'a>) -> Option<&'a Operation> {
 
 
 type SeekResult = Result<(), OTError>;
 type SeekResult = Result<(), OTError>;
 pub trait Metric {
 pub trait Metric {
-    fn seek(cursor: &mut OpCursor, index: usize) -> SeekResult;
+    fn seek<T: Attributes>(cursor: &mut OpCursor<T>, index: usize) -> SeekResult;
 }
 }
 
 
-pub struct OpMetric {}
+pub struct OpMetric();
 
 
 impl Metric for OpMetric {
 impl Metric for OpMetric {
-    fn seek(cursor: &mut OpCursor, index: usize) -> SeekResult {
+    fn seek<T: Attributes>(cursor: &mut OpCursor<T>, index: usize) -> SeekResult {
         let _ = check_bound(cursor.op_index, index)?;
         let _ = check_bound(cursor.op_index, index)?;
         let mut seek_cursor = OpCursor::new(cursor.delta, cursor.origin_iv);
         let mut seek_cursor = OpCursor::new(cursor.delta, cursor.origin_iv);
         let mut offset = 0;
         let mut offset = 0;
@@ -170,10 +176,10 @@ impl Metric for OpMetric {
     }
     }
 }
 }
 
 
-pub struct CharMetric {}
+pub struct CharMetric();
 
 
 impl Metric for CharMetric {
 impl Metric for CharMetric {
-    fn seek(cursor: &mut OpCursor, index: usize) -> SeekResult {
+    fn seek<T: Attributes>(cursor: &mut OpCursor<T>, index: usize) -> SeekResult {
         if index > 0 {
         if index > 0 {
             let _ = check_bound(cursor.consume_count, index)?;
             let _ = check_bound(cursor.consume_count, index)?;
             let _ = cursor.next_with_len(Some(index));
             let _ = cursor.next_with_len(Some(index));

+ 99 - 64
shared-lib/lib-ot/src/core/delta/delta.rs

@@ -3,6 +3,7 @@ use crate::{
     errors::{ErrorBuilder, OTError, OTErrorCode},
     errors::{ErrorBuilder, OTError, OTErrorCode},
 };
 };
 use bytes::Bytes;
 use bytes::Bytes;
+use serde::de::DeserializeOwned;
 use std::{
 use std::{
     cmp::{min, Ordering},
     cmp::{min, Ordering},
     fmt,
     fmt,
@@ -13,13 +14,16 @@ use std::{
 
 
 // Opti: optimize the memory usage with Arc_mut or Cow
 // Opti: optimize the memory usage with Arc_mut or Cow
 #[derive(Clone, Debug, PartialEq, Eq)]
 #[derive(Clone, Debug, PartialEq, Eq)]
-pub struct Delta {
-    pub ops: Vec<Operation>,
+pub struct Delta<T: Attributes> {
+    pub ops: Vec<Operation<T>>,
     pub base_len: usize,
     pub base_len: usize,
     pub target_len: usize,
     pub target_len: usize,
 }
 }
 
 
-impl Default for Delta {
+impl<T> Default for Delta<T>
+where
+    T: Attributes,
+{
     fn default() -> Self {
     fn default() -> Self {
         Self {
         Self {
             ops: Vec::new(),
             ops: Vec::new(),
@@ -29,28 +33,10 @@ impl Default for Delta {
     }
     }
 }
 }
 
 
-impl FromStr for Delta {
-    type Err = ();
-
-    fn from_str(s: &str) -> Result<Delta, Self::Err> {
-        let mut delta = Delta::with_capacity(1);
-        delta.add(Operation::Insert(s.into()));
-        Ok(delta)
-    }
-}
-
-impl std::convert::TryFrom<Vec<u8>> for Delta {
-    type Error = OTError;
-    fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> { Delta::from_bytes(bytes) }
-}
-
-impl std::convert::TryFrom<Bytes> for Delta {
-    type Error = OTError;
-
-    fn try_from(bytes: Bytes) -> Result<Self, Self::Error> { Delta::from_bytes(&bytes) }
-}
-
-impl fmt::Display for Delta {
+impl<T> fmt::Display for Delta<T>
+where
+    T: Attributes,
+{
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         // f.write_str(&serde_json::to_string(self).unwrap_or("".to_owned()))?;
         // f.write_str(&serde_json::to_string(self).unwrap_or("".to_owned()))?;
         f.write_str("[ ")?;
         f.write_str("[ ")?;
@@ -62,8 +48,11 @@ impl fmt::Display for Delta {
     }
     }
 }
 }
 
 
-impl FromIterator<Operation> for Delta {
-    fn from_iter<T: IntoIterator<Item = Operation>>(ops: T) -> Self {
+impl<T> FromIterator<Operation<T>> for Delta<T>
+where
+    T: Attributes,
+{
+    fn from_iter<I: IntoIterator<Item = Operation<T>>>(ops: I) -> Self {
         let mut operations = Delta::default();
         let mut operations = Delta::default();
         for op in ops {
         for op in ops {
             operations.add(op);
             operations.add(op);
@@ -72,30 +61,12 @@ impl FromIterator<Operation> for Delta {
     }
     }
 }
 }
 
 
-impl Delta {
+impl<T> Delta<T>
+where
+    T: Attributes,
+{
     pub fn new() -> Self { Self::default() }
     pub fn new() -> Self { Self::default() }
 
 
-    pub fn from_json(json: &str) -> Result<Self, OTError> {
-        let delta: Delta = serde_json::from_str(json).map_err(|e| {
-            tracing::trace!("Deserialize failed: {:?}", e);
-            tracing::trace!("{:?}", json);
-            e
-        })?;
-        Ok(delta)
-    }
-
-    pub fn to_json(&self) -> String { serde_json::to_string(self).unwrap_or_else(|_| "".to_owned()) }
-
-    pub fn from_bytes<T: AsRef<[u8]>>(bytes: T) -> Result<Self, OTError> {
-        let json = str::from_utf8(bytes.as_ref())?;
-        Self::from_json(json)
-    }
-
-    pub fn to_bytes(&self) -> Bytes {
-        let json = self.to_json();
-        Bytes::from(json.into_bytes())
-    }
-
     #[inline]
     #[inline]
     pub fn with_capacity(capacity: usize) -> Self {
     pub fn with_capacity(capacity: usize) -> Self {
         Self {
         Self {
@@ -105,7 +76,7 @@ impl Delta {
         }
         }
     }
     }
 
 
-    pub fn add(&mut self, op: Operation) {
+    pub fn add(&mut self, op: Operation<T>) {
         match op {
         match op {
             Operation::Delete(i) => self.delete(i),
             Operation::Delete(i) => self.delete(i),
             Operation::Insert(i) => self.insert(&i.s, i.attributes),
             Operation::Insert(i) => self.insert(&i.s, i.attributes),
@@ -125,7 +96,7 @@ impl Delta {
         }
         }
     }
     }
 
 
-    pub fn insert(&mut self, s: &str, attributes: Attributes) {
+    pub fn insert(&mut self, s: &str, attributes: T) {
         let s: FlowyStr = s.into();
         let s: FlowyStr = s.into();
         if s.is_empty() {
         if s.is_empty() {
             return;
             return;
@@ -133,20 +104,20 @@ impl Delta {
 
 
         self.target_len += s.count_utf16_code_units();
         self.target_len += s.count_utf16_code_units();
         let new_last = match self.ops.as_mut_slice() {
         let new_last = match self.ops.as_mut_slice() {
-            [.., Operation::Insert(insert)] => {
+            [.., Operation::<T>::Insert(insert)] => {
                 //
                 //
                 insert.merge_or_new_op(&s, attributes)
                 insert.merge_or_new_op(&s, attributes)
             },
             },
-            [.., Operation::Insert(pre_insert), Operation::Delete(_)] => {
+            [.., Operation::<T>::Insert(pre_insert), Operation::Delete(_)] => {
                 //
                 //
                 pre_insert.merge_or_new_op(&s, attributes)
                 pre_insert.merge_or_new_op(&s, attributes)
             },
             },
-            [.., op_last @ Operation::Delete(_)] => {
+            [.., op_last @ Operation::<T>::Delete(_)] => {
                 let new_last = op_last.clone();
                 let new_last = op_last.clone();
-                *op_last = OpBuilder::insert(&s).attributes(attributes).build();
+                *op_last = OpBuilder::<T>::insert(&s).attributes(attributes).build();
                 Some(new_last)
                 Some(new_last)
             },
             },
-            _ => Some(OpBuilder::insert(&s).attributes(attributes).build()),
+            _ => Some(OpBuilder::<T>::insert(&s).attributes(attributes).build()),
         };
         };
 
 
         match new_last {
         match new_last {
@@ -155,19 +126,19 @@ impl Delta {
         }
         }
     }
     }
 
 
-    pub fn retain(&mut self, n: usize, attributes: Attributes) {
+    pub fn retain(&mut self, n: usize, attributes: T) {
         if n == 0 {
         if n == 0 {
             return;
             return;
         }
         }
         self.base_len += n as usize;
         self.base_len += n as usize;
         self.target_len += n as usize;
         self.target_len += n as usize;
 
 
-        if let Some(Operation::Retain(retain)) = self.ops.last_mut() {
+        if let Some(Operation::<T>::Retain(retain)) = self.ops.last_mut() {
             if let Some(new_op) = retain.merge_or_new(n, attributes) {
             if let Some(new_op) = retain.merge_or_new(n, attributes) {
                 self.ops.push(new_op);
                 self.ops.push(new_op);
             }
             }
         } else {
         } else {
-            self.ops.push(OpBuilder::retain(n).attributes(attributes).build());
+            self.ops.push(OpBuilder::<T>::retain(n).attributes(attributes).build());
         }
         }
     }
     }
 
 
@@ -207,7 +178,7 @@ impl Delta {
         for op in &self.ops {
         for op in &self.ops {
             match &op {
             match &op {
                 Operation::Retain(retain) => {
                 Operation::Retain(retain) => {
-                    inverted.retain(retain.n, Attributes::default());
+                    inverted.retain(retain.n, T::default());
                     // TODO: use advance_by instead, but it's unstable now
                     // TODO: use advance_by instead, but it's unstable now
                     // chars.advance_by(retain.num)
                     // chars.advance_by(retain.num)
                     for _ in 0..retain.n {
                     for _ in 0..retain.n {
@@ -234,7 +205,10 @@ impl Delta {
     pub fn extend(&mut self, other: Self) { other.ops.into_iter().for_each(|op| self.add(op)); }
     pub fn extend(&mut self, other: Self) { other.ops.into_iter().for_each(|op| self.add(op)); }
 }
 }
 
 
-impl OperationTransformable for Delta {
+impl<T> OperationTransformable for Delta<T>
+where
+    T: Attributes,
+{
     fn compose(&self, other: &Self) -> Result<Self, OTError>
     fn compose(&self, other: &Self) -> Result<Self, OTError>
     where
     where
         Self: Sized,
         Self: Sized,
@@ -453,7 +427,13 @@ impl OperationTransformable for Delta {
     }
     }
 }
 }
 
 
-fn invert_from_other(base: &mut Delta, other: &Delta, operation: &Operation, start: usize, end: usize) {
+fn invert_from_other<T: Attributes>(
+    base: &mut Delta<T>,
+    other: &Delta<T>,
+    operation: &Operation<T>,
+    start: usize,
+    end: usize,
+) {
     tracing::trace!("invert op: {} [{}:{}]", operation, start, end);
     tracing::trace!("invert op: {} [{}:{}]", operation, start, end);
     let other_ops = DeltaIter::from_interval(other, Interval::new(start, end)).ops();
     let other_ops = DeltaIter::from_interval(other, Interval::new(start, end)).ops();
     other_ops.into_iter().for_each(|other_op| match operation {
     other_ops.into_iter().for_each(|other_op| match operation {
@@ -476,10 +456,10 @@ fn invert_from_other(base: &mut Delta, other: &Delta, operation: &Operation, sta
     });
     });
 }
 }
 
 
-fn transform_op_attribute(left: &Option<Operation>, right: &Option<Operation>) -> Attributes {
+fn transform_op_attribute<T: Attributes>(left: &Option<Operation<T>>, right: &Option<Operation<T>>) -> T {
     if left.is_none() {
     if left.is_none() {
         if right.is_none() {
         if right.is_none() {
-            return Attributes::default();
+            return T::default();
         }
         }
         return right.as_ref().unwrap().get_attributes();
         return right.as_ref().unwrap().get_attributes();
     }
     }
@@ -488,3 +468,58 @@ fn transform_op_attribute(left: &Option<Operation>, right: &Option<Operation>) -
     // TODO: It's ok to unwrap?
     // TODO: It's ok to unwrap?
     left.transform(&right).unwrap().0
     left.transform(&right).unwrap().0
 }
 }
+
+pub type RichTextDelta = Delta<RichTextAttributes>;
+
+impl<T> Delta<T>
+where
+    T: Attributes + DeserializeOwned,
+{
+    pub fn from_json(json: &str) -> Result<Self, OTError> {
+        let delta = serde_json::from_str(json).map_err(|e| {
+            tracing::trace!("Deserialize failed: {:?}", e);
+            tracing::trace!("{:?}", json);
+            e
+        })?;
+        Ok(delta)
+    }
+
+    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_json(&json)?;
+        Ok(val)
+    }
+}
+
+impl<T> Delta<T>
+where
+    T: Attributes + serde::Serialize,
+{
+    pub fn to_json(&self) -> String { serde_json::to_string(self).unwrap_or_else(|_| "".to_owned()) }
+
+    pub fn to_bytes(&self) -> Bytes {
+        let json = self.to_json();
+        Bytes::from(json.into_bytes())
+    }
+}
+
+impl FromStr for RichTextDelta {
+    type Err = ();
+
+    fn from_str(s: &str) -> Result<RichTextDelta, Self::Err> {
+        let mut delta = Delta::with_capacity(1);
+        delta.add(Operation::Insert(s.into()));
+        Ok(delta)
+    }
+}
+
+impl std::convert::TryFrom<Vec<u8>> for RichTextDelta {
+    type Error = OTError;
+    fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> { Delta::from_bytes(bytes) }
+}
+
+impl std::convert::TryFrom<Bytes> for RichTextDelta {
+    type Error = OTError;
+
+    fn try_from(bytes: Bytes) -> Result<Self, Self::Error> { Delta::from_bytes(&bytes) }
+}

+ 19 - 9
shared-lib/lib-ot/src/core/delta/delta_serde.rs

@@ -1,4 +1,4 @@
-use crate::core::Delta;
+use crate::core::{Attributes, Delta};
 use serde::{
 use serde::{
     de::{SeqAccess, Visitor},
     de::{SeqAccess, Visitor},
     ser::SerializeSeq,
     ser::SerializeSeq,
@@ -7,9 +7,12 @@ use serde::{
     Serialize,
     Serialize,
     Serializer,
     Serializer,
 };
 };
-use std::fmt;
+use std::{fmt, marker::PhantomData};
 
 
-impl Serialize for Delta {
+impl<T> Serialize for Delta<T>
+where
+    T: Attributes + Serialize,
+{
     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
     where
     where
         S: Serializer,
         S: Serializer,
@@ -22,18 +25,25 @@ impl Serialize for Delta {
     }
     }
 }
 }
 
 
-impl<'de> Deserialize<'de> for Delta {
-    fn deserialize<D>(deserializer: D) -> Result<Delta, D::Error>
+impl<'de, T> Deserialize<'de> for Delta<T>
+where
+    T: Attributes + Deserialize<'de>,
+{
+    fn deserialize<D>(deserializer: D) -> Result<Delta<T>, D::Error>
     where
     where
         D: Deserializer<'de>,
         D: Deserializer<'de>,
     {
     {
-        struct OperationSeqVisitor;
+        struct OperationSeqVisitor<T>(PhantomData<fn() -> T>);
 
 
-        impl<'de> Visitor<'de> for OperationSeqVisitor {
-            type Value = Delta;
+        impl<'de, T> Visitor<'de> for OperationSeqVisitor<T>
+        where
+            T: Attributes + Deserialize<'de>,
+        {
+            type Value = Delta<T>;
 
 
             fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("a sequence") }
             fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("a sequence") }
 
 
+            #[inline]
             fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
             fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
             where
             where
                 A: SeqAccess<'de>,
                 A: SeqAccess<'de>,
@@ -46,6 +56,6 @@ impl<'de> Deserialize<'de> for Delta {
             }
             }
         }
         }
 
 
-        deserializer.deserialize_seq(OperationSeqVisitor)
+        deserializer.deserialize_seq(OperationSeqVisitor(PhantomData))
     }
     }
 }
 }

+ 51 - 33
shared-lib/lib-ot/src/core/delta/iterator.rs

@@ -1,32 +1,35 @@
 use super::cursor::*;
 use super::cursor::*;
-use crate::core::{Attributes, Delta, Interval, Operation, NEW_LINE};
+use crate::core::{Attributes, Delta, Interval, Operation, RichTextAttributes, NEW_LINE};
 use std::ops::{Deref, DerefMut};
 use std::ops::{Deref, DerefMut};
 
 
 pub(crate) const MAX_IV_LEN: usize = i32::MAX as usize;
 pub(crate) const MAX_IV_LEN: usize = i32::MAX as usize;
 
 
-pub struct DeltaIter<'a> {
-    cursor: OpCursor<'a>,
+pub struct DeltaIter<'a, T: Attributes> {
+    cursor: OpCursor<'a, T>,
 }
 }
 
 
-impl<'a> DeltaIter<'a> {
-    pub fn new(delta: &'a Delta) -> Self {
+impl<'a, T> DeltaIter<'a, T>
+where
+    T: Attributes,
+{
+    pub fn new(delta: &'a Delta<T>) -> Self {
         let interval = Interval::new(0, MAX_IV_LEN);
         let interval = Interval::new(0, MAX_IV_LEN);
         Self::from_interval(delta, interval)
         Self::from_interval(delta, interval)
     }
     }
 
 
-    pub fn from_offset(delta: &'a Delta, offset: usize) -> Self {
+    pub fn from_offset(delta: &'a Delta<T>, offset: usize) -> Self {
         let interval = Interval::new(0, MAX_IV_LEN);
         let interval = Interval::new(0, MAX_IV_LEN);
         let mut iter = Self::from_interval(delta, interval);
         let mut iter = Self::from_interval(delta, interval);
         iter.seek::<CharMetric>(offset);
         iter.seek::<CharMetric>(offset);
         iter
         iter
     }
     }
 
 
-    pub fn from_interval(delta: &'a Delta, interval: Interval) -> Self {
+    pub fn from_interval(delta: &'a Delta<T>, interval: Interval) -> Self {
         let cursor = OpCursor::new(delta, interval);
         let cursor = OpCursor::new(delta, interval);
         Self { cursor }
         Self { cursor }
     }
     }
 
 
-    pub fn ops(&mut self) -> Vec<Operation> { self.collect::<Vec<_>>() }
+    pub fn ops(&mut self) -> Vec<Operation<T>> { self.collect::<Vec<_>>() }
 
 
     pub fn next_op_len(&self) -> Option<usize> {
     pub fn next_op_len(&self) -> Option<usize> {
         let interval = self.cursor.next_iv();
         let interval = self.cursor.next_iv();
@@ -37,12 +40,12 @@ impl<'a> DeltaIter<'a> {
         }
         }
     }
     }
 
 
-    pub fn next_op(&mut self) -> Option<Operation> { self.cursor.next_op() }
+    pub fn next_op(&mut self) -> Option<Operation<T>> { self.cursor.next_op() }
 
 
-    pub fn next_op_with_len(&mut self, len: usize) -> Option<Operation> { self.cursor.next_with_len(Some(len)) }
+    pub fn next_op_with_len(&mut self, len: usize) -> Option<Operation<T>> { self.cursor.next_with_len(Some(len)) }
 
 
     // find next op contains NEW_LINE
     // find next op contains NEW_LINE
-    pub fn next_op_with_newline(&mut self) -> Option<(Operation, usize)> {
+    pub fn next_op_with_newline(&mut self) -> Option<(Operation<T>, usize)> {
         let mut offset = 0;
         let mut offset = 0;
         while self.has_next() {
         while self.has_next() {
             if let Some(op) = self.next_op() {
             if let Some(op) = self.next_op() {
@@ -87,12 +90,15 @@ impl<'a> DeltaIter<'a> {
     }
     }
 }
 }
 
 
-impl<'a> Iterator for DeltaIter<'a> {
-    type Item = Operation;
+impl<'a, T> Iterator for DeltaIter<'a, T>
+where
+    T: Attributes,
+{
+    type Item = Operation<T>;
     fn next(&mut self) -> Option<Self::Item> { self.next_op() }
     fn next(&mut self) -> Option<Self::Item> { self.next_op() }
 }
 }
 
 
-pub fn is_empty_line_at_index(delta: &Delta, index: usize) -> bool {
+pub fn is_empty_line_at_index(delta: &Delta<RichTextAttributes>, index: usize) -> bool {
     let mut iter = DeltaIter::new(delta);
     let mut iter = DeltaIter::new(delta);
     let (prev, next) = (iter.next_op_with_len(index), iter.next_op());
     let (prev, next) = (iter.next_op_with_len(index), iter.next_op());
     if prev.is_none() {
     if prev.is_none() {
@@ -108,58 +114,70 @@ pub fn is_empty_line_at_index(delta: &Delta, index: usize) -> bool {
     OpNewline::parse(&prev).is_end() && OpNewline::parse(&next).is_start()
     OpNewline::parse(&prev).is_end() && OpNewline::parse(&next).is_start()
 }
 }
 
 
-pub struct AttributesIter<'a> {
-    delta_iter: DeltaIter<'a>,
+pub struct AttributesIter<'a, T: Attributes> {
+    delta_iter: DeltaIter<'a, T>,
 }
 }
 
 
-impl<'a> AttributesIter<'a> {
-    pub fn new(delta: &'a Delta) -> Self {
+impl<'a, T> AttributesIter<'a, T>
+where
+    T: Attributes,
+{
+    pub fn new(delta: &'a Delta<T>) -> Self {
         let interval = Interval::new(0, usize::MAX);
         let interval = Interval::new(0, usize::MAX);
         Self::from_interval(delta, interval)
         Self::from_interval(delta, interval)
     }
     }
 
 
-    pub fn from_interval(delta: &'a Delta, interval: Interval) -> Self {
+    pub fn from_interval(delta: &'a Delta<T>, interval: Interval) -> Self {
         let delta_iter = DeltaIter::from_interval(delta, interval);
         let delta_iter = DeltaIter::from_interval(delta, interval);
         Self { delta_iter }
         Self { delta_iter }
     }
     }
 
 
-    pub fn next_or_empty(&mut self) -> Attributes {
+    pub fn next_or_empty(&mut self) -> T {
         match self.next() {
         match self.next() {
-            None => Attributes::default(),
+            None => T::default(),
             Some((_, attributes)) => attributes,
             Some((_, attributes)) => attributes,
         }
         }
     }
     }
 }
 }
 
 
-impl<'a> Deref for AttributesIter<'a> {
-    type Target = DeltaIter<'a>;
+impl<'a, T> Deref for AttributesIter<'a, T>
+where
+    T: Attributes,
+{
+    type Target = DeltaIter<'a, T>;
 
 
     fn deref(&self) -> &Self::Target { &self.delta_iter }
     fn deref(&self) -> &Self::Target { &self.delta_iter }
 }
 }
 
 
-impl<'a> DerefMut for AttributesIter<'a> {
+impl<'a, T> DerefMut for AttributesIter<'a, T>
+where
+    T: Attributes,
+{
     fn deref_mut(&mut self) -> &mut Self::Target { &mut self.delta_iter }
     fn deref_mut(&mut self) -> &mut Self::Target { &mut self.delta_iter }
 }
 }
 
 
-impl<'a> Iterator for AttributesIter<'a> {
-    type Item = (usize, Attributes);
+impl<'a, T> Iterator for AttributesIter<'a, T>
+where
+    T: Attributes,
+{
+    type Item = (usize, T);
     fn next(&mut self) -> Option<Self::Item> {
     fn next(&mut self) -> Option<Self::Item> {
         let next_op = self.delta_iter.next_op();
         let next_op = self.delta_iter.next_op();
         next_op.as_ref()?;
         next_op.as_ref()?;
         let mut length: usize = 0;
         let mut length: usize = 0;
-        let mut attributes = Attributes::new();
+        let mut attributes = T::default();
 
 
         match next_op.unwrap() {
         match next_op.unwrap() {
-            Operation::Delete(_n) => {},
-            Operation::Retain(retain) => {
+            Operation::<T>::Delete(_n) => {},
+            Operation::<T>::Retain(retain) => {
                 tracing::trace!("extend retain attributes with {} ", &retain.attributes);
                 tracing::trace!("extend retain attributes with {} ", &retain.attributes);
-                attributes.extend(retain.attributes.clone());
+                attributes.extend_other(retain.attributes.clone());
 
 
                 length = retain.n;
                 length = retain.n;
             },
             },
-            Operation::Insert(insert) => {
+            Operation::<T>::Insert(insert) => {
                 tracing::trace!("extend insert attributes with {} ", &insert.attributes);
                 tracing::trace!("extend insert attributes with {} ", &insert.attributes);
-                attributes.extend(insert.attributes.clone());
+                attributes.extend_other(insert.attributes.clone());
                 length = insert.count_of_code_units();
                 length = insert.count_of_code_units();
             },
             },
         }
         }
@@ -178,7 +196,7 @@ pub enum OpNewline {
 }
 }
 
 
 impl OpNewline {
 impl OpNewline {
-    pub fn parse(op: &Operation) -> OpNewline {
+    pub fn parse<T: Attributes>(op: &Operation<T>) -> OpNewline {
         let s = op.get_data();
         let s = op.get_data();
 
 
         if s == NEW_LINE {
         if s == NEW_LINE {

+ 17 - 12
shared-lib/lib-ot/src/core/operation/builder.rs

@@ -1,30 +1,35 @@
-use crate::core::{Attributes, Operation};
+use crate::core::{Attributes, Operation, RichTextAttributes};
 
 
-pub struct OpBuilder {
-    ty: Operation,
-    attrs: Attributes,
+pub type RichTextOpBuilder = OpBuilder<RichTextAttributes>;
+
+pub struct OpBuilder<T: Attributes> {
+    ty: Operation<T>,
+    attrs: T,
 }
 }
 
 
-impl OpBuilder {
-    pub fn new(ty: Operation) -> OpBuilder {
+impl<T> OpBuilder<T>
+where
+    T: Attributes,
+{
+    pub fn new(ty: Operation<T>) -> OpBuilder<T> {
         OpBuilder {
         OpBuilder {
             ty,
             ty,
-            attrs: Attributes::default(),
+            attrs: T::default(),
         }
         }
     }
     }
 
 
-    pub fn retain(n: usize) -> OpBuilder { OpBuilder::new(Operation::Retain(n.into())) }
+    pub fn retain(n: usize) -> OpBuilder<T> { OpBuilder::new(Operation::Retain(n.into())) }
 
 
-    pub fn delete(n: usize) -> OpBuilder { OpBuilder::new(Operation::Delete(n)) }
+    pub fn delete(n: usize) -> OpBuilder<T> { OpBuilder::new(Operation::Delete(n)) }
 
 
-    pub fn insert(s: &str) -> OpBuilder { OpBuilder::new(Operation::Insert(s.into())) }
+    pub fn insert(s: &str) -> OpBuilder<T> { OpBuilder::new(Operation::Insert(s.into())) }
 
 
-    pub fn attributes(mut self, attrs: Attributes) -> OpBuilder {
+    pub fn attributes(mut self, attrs: T) -> OpBuilder<T> {
         self.attrs = attrs;
         self.attrs = attrs;
         self
         self
     }
     }
 
 
-    pub fn build(self) -> Operation {
+    pub fn build(self) -> Operation<T> {
         let mut operation = self.ty;
         let mut operation = self.ty;
         match &mut operation {
         match &mut operation {
             Operation::Delete(_) => {},
             Operation::Delete(_) => {},

+ 96 - 49
shared-lib/lib-ot/src/core/operation/operation.rs

@@ -1,19 +1,39 @@
-use crate::core::{Attribute, Attributes, FlowyStr, Interval, OpBuilder};
+use crate::core::{FlowyStr, Interval, OpBuilder, OperationTransformable, RichTextAttribute, RichTextAttributes};
 use serde::__private::Formatter;
 use serde::__private::Formatter;
 use std::{
 use std::{
     cmp::min,
     cmp::min,
     fmt,
     fmt,
+    fmt::Debug,
     ops::{Deref, DerefMut},
     ops::{Deref, DerefMut},
 };
 };
 
 
+pub trait Attributes: fmt::Display + Eq + PartialEq + Default + Clone + Debug + OperationTransformable {
+    fn is_empty(&self) -> bool;
+
+    // Remove the empty attribute which value is None.
+    fn remove_empty(&mut self);
+
+    fn extend_other(&mut self, other: Self);
+}
+
+pub type RichTextOperation = Operation<RichTextAttributes>;
+impl RichTextOperation {
+    pub fn contain_attribute(&self, attribute: &RichTextAttribute) -> bool {
+        self.get_attributes().contains_key(&attribute.key)
+    }
+}
+
 #[derive(Debug, Clone, Eq, PartialEq)]
 #[derive(Debug, Clone, Eq, PartialEq)]
-pub enum Operation {
+pub enum Operation<T: Attributes> {
     Delete(usize),
     Delete(usize),
-    Retain(Retain),
-    Insert(Insert),
+    Retain(Retain<T>),
+    Insert(Insert<T>),
 }
 }
 
 
-impl Operation {
+impl<T> Operation<T>
+where
+    T: Attributes,
+{
     pub fn get_data(&self) -> &str {
     pub fn get_data(&self) -> &str {
         match self {
         match self {
             Operation::Delete(_) => "",
             Operation::Delete(_) => "",
@@ -22,15 +42,15 @@ impl Operation {
         }
         }
     }
     }
 
 
-    pub fn get_attributes(&self) -> Attributes {
+    pub fn get_attributes(&self) -> T {
         match self {
         match self {
-            Operation::Delete(_) => Attributes::default(),
+            Operation::Delete(_) => T::default(),
             Operation::Retain(retain) => retain.attributes.clone(),
             Operation::Retain(retain) => retain.attributes.clone(),
             Operation::Insert(insert) => insert.attributes.clone(),
             Operation::Insert(insert) => insert.attributes.clone(),
         }
         }
     }
     }
 
 
-    pub fn set_attributes(&mut self, attributes: Attributes) {
+    pub fn set_attributes(&mut self, attributes: T) {
         match self {
         match self {
             Operation::Delete(_) => log::error!("Delete should not contains attributes"),
             Operation::Delete(_) => log::error!("Delete should not contains attributes"),
             Operation::Retain(retain) => retain.attributes = attributes,
             Operation::Retain(retain) => retain.attributes = attributes,
@@ -40,10 +60,6 @@ impl Operation {
 
 
     pub fn has_attribute(&self) -> bool { !self.get_attributes().is_empty() }
     pub fn has_attribute(&self) -> bool { !self.get_attributes().is_empty() }
 
 
-    pub fn contain_attribute(&self, attribute: &Attribute) -> bool {
-        self.get_attributes().contains_key(&attribute.key)
-    }
-
     pub fn len(&self) -> usize {
     pub fn len(&self) -> usize {
         match self {
         match self {
             Operation::Delete(n) => *n,
             Operation::Delete(n) => *n,
@@ -55,28 +71,28 @@ impl Operation {
     pub fn is_empty(&self) -> bool { self.len() == 0 }
     pub fn is_empty(&self) -> bool { self.len() == 0 }
 
 
     #[allow(dead_code)]
     #[allow(dead_code)]
-    pub fn split(&self, index: usize) -> (Option<Operation>, Option<Operation>) {
+    pub fn split(&self, index: usize) -> (Option<Operation<T>>, Option<Operation<T>>) {
         debug_assert!(index < self.len());
         debug_assert!(index < self.len());
         let left;
         let left;
         let right;
         let right;
         match self {
         match self {
             Operation::Delete(n) => {
             Operation::Delete(n) => {
-                left = Some(OpBuilder::delete(index).build());
-                right = Some(OpBuilder::delete(*n - index).build());
+                left = Some(OpBuilder::<T>::delete(index).build());
+                right = Some(OpBuilder::<T>::delete(*n - index).build());
             },
             },
             Operation::Retain(retain) => {
             Operation::Retain(retain) => {
-                left = Some(OpBuilder::delete(index).build());
-                right = Some(OpBuilder::delete(retain.n - index).build());
+                left = Some(OpBuilder::<T>::delete(index).build());
+                right = Some(OpBuilder::<T>::delete(retain.n - index).build());
             },
             },
             Operation::Insert(insert) => {
             Operation::Insert(insert) => {
                 let attributes = self.get_attributes();
                 let attributes = self.get_attributes();
                 left = Some(
                 left = Some(
-                    OpBuilder::insert(&insert.s[0..index])
+                    OpBuilder::<T>::insert(&insert.s[0..index])
                         .attributes(attributes.clone())
                         .attributes(attributes.clone())
                         .build(),
                         .build(),
                 );
                 );
                 right = Some(
                 right = Some(
-                    OpBuilder::insert(&insert.s[index..insert.count_of_code_units()])
+                    OpBuilder::<T>::insert(&insert.s[index..insert.count_of_code_units()])
                         .attributes(attributes)
                         .attributes(attributes)
                         .build(),
                         .build(),
                 );
                 );
@@ -86,7 +102,7 @@ impl Operation {
         (left, right)
         (left, right)
     }
     }
 
 
-    pub fn shrink(&self, interval: Interval) -> Option<Operation> {
+    pub fn shrink(&self, interval: Interval) -> Option<Operation<T>> {
         let op = match self {
         let op = match self {
             Operation::Delete(n) => OpBuilder::delete(min(*n, interval.size())).build(),
             Operation::Delete(n) => OpBuilder::delete(min(*n, interval.size())).build(),
             Operation::Retain(retain) => OpBuilder::retain(min(retain.n, interval.size()))
             Operation::Retain(retain) => OpBuilder::retain(min(retain.n, interval.size()))
@@ -145,7 +161,10 @@ impl Operation {
     }
     }
 }
 }
 
 
-impl fmt::Display for Operation {
+impl<T> fmt::Display for Operation<T>
+where
+    T: Attributes,
+{
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.write_str("{")?;
         f.write_str("{")?;
         match self {
         match self {
@@ -164,15 +183,18 @@ impl fmt::Display for Operation {
     }
     }
 }
 }
 
 
-#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
-pub struct Retain {
-    #[serde(rename(serialize = "retain", deserialize = "retain"))]
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct Retain<T: Attributes> {
+    // #[serde(rename(serialize = "retain", deserialize = "retain"))]
     pub n: usize,
     pub n: usize,
-    #[serde(skip_serializing_if = "is_empty")]
-    pub attributes: Attributes,
+    // #[serde(skip_serializing_if = "is_empty")]
+    pub attributes: T,
 }
 }
 
 
-impl fmt::Display for Retain {
+impl<T> fmt::Display for Retain<T>
+where
+    T: Attributes,
+{
     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
         if self.attributes.is_empty() {
         if self.attributes.is_empty() {
             f.write_fmt(format_args!("retain: {}", self.n))
             f.write_fmt(format_args!("retain: {}", self.n))
@@ -182,8 +204,11 @@ impl fmt::Display for Retain {
     }
     }
 }
 }
 
 
-impl Retain {
-    pub fn merge_or_new(&mut self, n: usize, attributes: Attributes) -> Option<Operation> {
+impl<T> Retain<T>
+where
+    T: Attributes,
+{
+    pub fn merge_or_new(&mut self, n: usize, attributes: T) -> Option<Operation<T>> {
         tracing::trace!(
         tracing::trace!(
             "merge_retain_or_new_op: len: {:?}, l: {} - r: {}",
             "merge_retain_or_new_op: len: {:?}, l: {} - r: {}",
             n,
             n,
@@ -201,35 +226,47 @@ impl Retain {
     pub fn is_plain(&self) -> bool { self.attributes.is_empty() }
     pub fn is_plain(&self) -> bool { self.attributes.is_empty() }
 }
 }
 
 
-impl std::convert::From<usize> for Retain {
+impl<T> std::convert::From<usize> for Retain<T>
+where
+    T: Attributes,
+{
     fn from(n: usize) -> Self {
     fn from(n: usize) -> Self {
         Retain {
         Retain {
             n,
             n,
-            attributes: Attributes::default(),
+            attributes: T::default(),
         }
         }
     }
     }
 }
 }
 
 
-impl Deref for Retain {
+impl<T> Deref for Retain<T>
+where
+    T: Attributes,
+{
     type Target = usize;
     type Target = usize;
 
 
     fn deref(&self) -> &Self::Target { &self.n }
     fn deref(&self) -> &Self::Target { &self.n }
 }
 }
 
 
-impl DerefMut for Retain {
+impl<T> DerefMut for Retain<T>
+where
+    T: Attributes,
+{
     fn deref_mut(&mut self) -> &mut Self::Target { &mut self.n }
     fn deref_mut(&mut self) -> &mut Self::Target { &mut self.n }
 }
 }
 
 
-#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
-pub struct Insert {
-    #[serde(rename(serialize = "insert", deserialize = "insert"))]
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct Insert<T: Attributes> {
+    // #[serde(rename(serialize = "insert", deserialize = "insert"))]
     pub s: FlowyStr,
     pub s: FlowyStr,
 
 
-    #[serde(skip_serializing_if = "is_empty")]
-    pub attributes: Attributes,
+    // #[serde(skip_serializing_if = "is_empty")]
+    pub attributes: T,
 }
 }
 
 
-impl fmt::Display for Insert {
+impl<T> fmt::Display for Insert<T>
+where
+    T: Attributes,
+{
     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
         let mut s = self.s.clone();
         let mut s = self.s.clone();
         if s.ends_with('\n') {
         if s.ends_with('\n') {
@@ -247,41 +284,51 @@ impl fmt::Display for Insert {
     }
     }
 }
 }
 
 
-impl Insert {
+impl<T> Insert<T>
+where
+    T: Attributes,
+{
     pub fn count_of_code_units(&self) -> usize { self.s.count_utf16_code_units() }
     pub fn count_of_code_units(&self) -> usize { self.s.count_utf16_code_units() }
 
 
-    pub fn merge_or_new_op(&mut self, s: &str, attributes: Attributes) -> Option<Operation> {
+    pub fn merge_or_new_op(&mut self, s: &str, attributes: T) -> Option<Operation<T>> {
         if self.attributes == attributes {
         if self.attributes == attributes {
             self.s += s;
             self.s += s;
             None
             None
         } else {
         } else {
-            Some(OpBuilder::insert(s).attributes(attributes).build())
+            Some(OpBuilder::<T>::insert(s).attributes(attributes).build())
         }
         }
     }
     }
 
 
     pub fn is_plain(&self) -> bool { self.attributes.is_empty() }
     pub fn is_plain(&self) -> bool { self.attributes.is_empty() }
 }
 }
 
 
-impl std::convert::From<String> for Insert {
+impl<T> std::convert::From<String> for Insert<T>
+where
+    T: Attributes,
+{
     fn from(s: String) -> Self {
     fn from(s: String) -> Self {
         Insert {
         Insert {
             s: s.into(),
             s: s.into(),
-            attributes: Attributes::default(),
+            attributes: T::default(),
         }
         }
     }
     }
 }
 }
 
 
-impl std::convert::From<&str> for Insert {
+impl<T> std::convert::From<&str> for Insert<T>
+where
+    T: Attributes,
+{
     fn from(s: &str) -> Self { Insert::from(s.to_owned()) }
     fn from(s: &str) -> Self { Insert::from(s.to_owned()) }
 }
 }
 
 
-impl std::convert::From<FlowyStr> for Insert {
+impl<T> std::convert::From<FlowyStr> for Insert<T>
+where
+    T: Attributes,
+{
     fn from(s: FlowyStr) -> Self {
     fn from(s: FlowyStr) -> Self {
         Insert {
         Insert {
             s,
             s,
-            attributes: Attributes::default(),
+            attributes: T::default(),
         }
         }
     }
     }
 }
 }
-
-fn is_empty(attributes: &Attributes) -> bool { attributes.is_empty() }

+ 226 - 14
shared-lib/lib-ot/src/core/operation/operation_serde.rs

@@ -1,16 +1,19 @@
-use crate::core::{Attributes, Operation};
+use crate::core::{Attributes, FlowyStr, Insert, Operation, Retain};
 use serde::{
 use serde::{
     de,
     de,
-    de::{MapAccess, Visitor},
+    de::{MapAccess, SeqAccess, Visitor},
     ser::SerializeMap,
     ser::SerializeMap,
     Deserialize,
     Deserialize,
     Deserializer,
     Deserializer,
     Serialize,
     Serialize,
     Serializer,
     Serializer,
 };
 };
-use std::fmt;
+use std::{fmt, marker::PhantomData};
 
 
-impl Serialize for Operation {
+impl<T> Serialize for Operation<T>
+where
+    T: Attributes + Serialize,
+{
     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
     where
     where
         S: Serializer,
         S: Serializer,
@@ -27,20 +30,27 @@ impl Serialize for Operation {
     }
     }
 }
 }
 
 
-impl<'de> Deserialize<'de> for Operation {
-    fn deserialize<D>(deserializer: D) -> Result<Operation, D::Error>
+impl<'de, T> Deserialize<'de> for Operation<T>
+where
+    T: Attributes + Deserialize<'de>,
+{
+    fn deserialize<D>(deserializer: D) -> Result<Operation<T>, D::Error>
     where
     where
         D: Deserializer<'de>,
         D: Deserializer<'de>,
     {
     {
-        struct OperationVisitor;
+        struct OperationVisitor<T>(PhantomData<fn() -> T>);
 
 
-        impl<'de> Visitor<'de> for OperationVisitor {
-            type Value = Operation;
+        impl<'de, T> Visitor<'de> for OperationVisitor<T>
+        where
+            T: Attributes + Deserialize<'de>,
+        {
+            type Value = Operation<T>;
 
 
             fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
             fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                 formatter.write_str("an integer between -2^64 and 2^63 or a string")
                 formatter.write_str("an integer between -2^64 and 2^63 or a string")
             }
             }
 
 
+            #[inline]
             fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
             fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
             where
             where
                 V: MapAccess<'de>,
                 V: MapAccess<'de>,
@@ -53,27 +63,27 @@ impl<'de> Deserialize<'de> for Operation {
                             if operation.is_some() {
                             if operation.is_some() {
                                 return Err(de::Error::duplicate_field("operation"));
                                 return Err(de::Error::duplicate_field("operation"));
                             }
                             }
-                            operation = Some(Operation::Delete(map.next_value()?));
+                            operation = Some(Operation::<T>::Delete(map.next_value()?));
                         },
                         },
                         "retain" => {
                         "retain" => {
                             if operation.is_some() {
                             if operation.is_some() {
                                 return Err(de::Error::duplicate_field("operation"));
                                 return Err(de::Error::duplicate_field("operation"));
                             }
                             }
                             let i: usize = map.next_value()?;
                             let i: usize = map.next_value()?;
-                            operation = Some(Operation::Retain(i.into()));
+                            operation = Some(Operation::<T>::Retain(i.into()));
                         },
                         },
                         "insert" => {
                         "insert" => {
                             if operation.is_some() {
                             if operation.is_some() {
                                 return Err(de::Error::duplicate_field("operation"));
                                 return Err(de::Error::duplicate_field("operation"));
                             }
                             }
                             let i: String = map.next_value()?;
                             let i: String = map.next_value()?;
-                            operation = Some(Operation::Insert(i.into()));
+                            operation = Some(Operation::<T>::Insert(i.into()));
                         },
                         },
                         "attributes" => {
                         "attributes" => {
                             if attributes.is_some() {
                             if attributes.is_some() {
                                 return Err(de::Error::duplicate_field("attributes"));
                                 return Err(de::Error::duplicate_field("attributes"));
                             }
                             }
-                            let map: Attributes = map.next_value()?;
+                            let map: T = map.next_value()?;
                             attributes = Some(map);
                             attributes = Some(map);
                         },
                         },
                         _ => panic!(),
                         _ => panic!(),
@@ -91,6 +101,208 @@ impl<'de> Deserialize<'de> for Operation {
             }
             }
         }
         }
 
 
-        deserializer.deserialize_any(OperationVisitor)
+        deserializer.deserialize_any(OperationVisitor(PhantomData))
+    }
+}
+
+impl<T> Serialize for Retain<T>
+where
+    T: Attributes + Serialize,
+{
+    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+    where
+        S: Serializer,
+    {
+        let len = false as usize + 1 + if self.attributes.is_empty() { 0 } else { 1 };
+        let mut serde_state = serializer.serialize_struct("Retain", len)?;
+        let _ = serde::ser::SerializeStruct::serialize_field(&mut serde_state, "retain", &self.n)?;
+        if !self.attributes.is_empty() {
+            let _ = serde::ser::SerializeStruct::serialize_field(&mut serde_state, "attributes", &self.attributes)?;
+        }
+        serde::ser::SerializeStruct::end(serde_state)
+    }
+}
+
+impl<'de, T> Deserialize<'de> for Retain<T>
+where
+    T: Attributes + Deserialize<'de>,
+{
+    fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        struct RetainVisitor<T>(PhantomData<fn() -> T>);
+
+        impl<'de, T> Visitor<'de> for RetainVisitor<T>
+        where
+            T: Attributes + Deserialize<'de>,
+        {
+            type Value = Retain<T>;
+
+            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("struct Retain") }
+
+            #[inline]
+            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
+            where
+                A: SeqAccess<'de>,
+            {
+                let len = match serde::de::SeqAccess::next_element::<usize>(&mut seq)? {
+                    Some(val) => val,
+                    None => {
+                        return Err(de::Error::invalid_length(0, &"struct Retain with 2 elements"));
+                    },
+                };
+
+                let attributes = match serde::de::SeqAccess::next_element::<T>(&mut seq)? {
+                    Some(val) => val,
+                    None => {
+                        return Err(de::Error::invalid_length(1, &"struct Retain with 2 elements"));
+                    },
+                };
+
+                Ok(Retain::<T> { n: len, attributes })
+            }
+
+            #[inline]
+            fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
+            where
+                V: MapAccess<'de>,
+            {
+                let mut len: Option<usize> = None;
+                let mut attributes: Option<T> = None;
+                while let Some(key) = map.next_key()? {
+                    match key {
+                        "retain" => {
+                            if len.is_some() {
+                                return Err(de::Error::duplicate_field("retain"));
+                            }
+                            len = Some(map.next_value()?);
+                        },
+                        "attributes" => {
+                            if attributes.is_some() {
+                                return Err(de::Error::duplicate_field("attributes"));
+                            }
+                            attributes = Some(map.next_value()?);
+                        },
+                        _ => panic!(),
+                    }
+                }
+
+                if len.is_none() {
+                    return Err(de::Error::missing_field("len"));
+                }
+
+                if attributes.is_none() {
+                    return Err(de::Error::missing_field("attributes"));
+                }
+                Ok(Retain::<T> {
+                    n: len.unwrap(),
+                    attributes: attributes.unwrap(),
+                })
+            }
+        }
+        const FIELDS: &[&str] = &["retain", "attributes"];
+        serde::Deserializer::deserialize_struct(deserializer, "Retain", FIELDS, RetainVisitor(PhantomData))
+    }
+}
+
+impl<T> Serialize for Insert<T>
+where
+    T: Attributes + Serialize,
+{
+    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+    where
+        S: Serializer,
+    {
+        let len = false as usize + 1 + if self.attributes.is_empty() { 0 } else { 1 };
+        let mut serde_state = serializer.serialize_struct("Insert", len)?;
+        let _ = serde::ser::SerializeStruct::serialize_field(&mut serde_state, "insert", &self.s)?;
+        if !self.attributes.is_empty() {
+            let _ = serde::ser::SerializeStruct::serialize_field(&mut serde_state, "attributes", &self.attributes)?;
+        }
+        serde::ser::SerializeStruct::end(serde_state)
+    }
+}
+
+impl<'de, T> Deserialize<'de> for Insert<T>
+where
+    T: Attributes + Deserialize<'de>,
+{
+    fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        struct InsertVisitor<T>(PhantomData<fn() -> T>);
+
+        impl<'de, T> Visitor<'de> for InsertVisitor<T>
+        where
+            T: Attributes + Deserialize<'de>,
+        {
+            type Value = Insert<T>;
+
+            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("struct Insert") }
+
+            #[inline]
+            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
+            where
+                A: SeqAccess<'de>,
+            {
+                let s = match serde::de::SeqAccess::next_element::<FlowyStr>(&mut seq)? {
+                    Some(val) => val,
+                    None => {
+                        return Err(de::Error::invalid_length(0, &"struct Insert with 2 elements"));
+                    },
+                };
+
+                let attributes = match serde::de::SeqAccess::next_element::<T>(&mut seq)? {
+                    Some(val) => val,
+                    None => {
+                        return Err(de::Error::invalid_length(1, &"struct Retain with 2 elements"));
+                    },
+                };
+
+                Ok(Insert::<T> { s, attributes })
+            }
+
+            #[inline]
+            fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
+            where
+                V: MapAccess<'de>,
+            {
+                let mut s: Option<FlowyStr> = None;
+                let mut attributes: Option<T> = None;
+                while let Some(key) = map.next_key()? {
+                    match key {
+                        "insert" => {
+                            if s.is_some() {
+                                return Err(de::Error::duplicate_field("insert"));
+                            }
+                            s = Some(map.next_value()?);
+                        },
+                        "attributes" => {
+                            if attributes.is_some() {
+                                return Err(de::Error::duplicate_field("attributes"));
+                            }
+                            attributes = Some(map.next_value()?);
+                        },
+                        _ => panic!(),
+                    }
+                }
+
+                if s.is_none() {
+                    return Err(de::Error::missing_field("s"));
+                }
+
+                if attributes.is_none() {
+                    return Err(de::Error::missing_field("attributes"));
+                }
+                Ok(Insert::<T> {
+                    s: s.unwrap(),
+                    attributes: attributes.unwrap(),
+                })
+            }
+        }
+        const FIELDS: &[&str] = &["insert", "attributes"];
+        serde::Deserializer::deserialize_struct(deserializer, "Insert", FIELDS, InsertVisitor(PhantomData))
     }
     }
 }
 }