Merge pull request #1033 from AppFlowy-IO/feat/lib_ot_directory

Feat/lib ot directory
This commit is contained in:
Nathan.fooo 2022-09-12 11:06:54 +08:00 committed by GitHub
commit 944b2d97cd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
73 changed files with 510 additions and 519 deletions

View File

@ -1778,6 +1778,7 @@ dependencies = [
"md5", "md5",
"serde", "serde",
"serde_json", "serde_json",
"serde_repr",
"strum", "strum",
"strum_macros", "strum_macros",
"thiserror", "thiserror",

View File

@ -13,7 +13,7 @@ use flowy_folder_data_model::revision::{AppRevision, TrashRevision, ViewRevision
use flowy_revision::disk::{RevisionRecord, RevisionState}; use flowy_revision::disk::{RevisionRecord, RevisionState};
use flowy_revision::mk_text_block_revision_disk_cache; use flowy_revision::mk_text_block_revision_disk_cache;
use flowy_sync::{client_folder::FolderPad, entities::revision::Revision}; use flowy_sync::{client_folder::FolderPad, entities::revision::Revision};
use lib_ot::core::TextDeltaBuilder; use lib_ot::core::DeltaBuilder;
use std::sync::Arc; use std::sync::Arc;
use tokio::sync::RwLock; use tokio::sync::RwLock;
pub use version_1::{app_sql::*, trash_sql::*, v1_impl::V1Transaction, view_sql::*, workspace_sql::*}; pub use version_1::{app_sql::*, trash_sql::*, v1_impl::V1Transaction, view_sql::*, workspace_sql::*};
@ -109,7 +109,7 @@ impl FolderPersistence {
pub async fn save_folder(&self, user_id: &str, folder_id: &FolderId, folder: FolderPad) -> FlowyResult<()> { pub async fn save_folder(&self, user_id: &str, folder_id: &FolderId, folder: FolderPad) -> FlowyResult<()> {
let pool = self.database.db_pool()?; let pool = self.database.db_pool()?;
let json = folder.to_json()?; let json = folder.to_json()?;
let delta_data = TextDeltaBuilder::new().insert(&json).build().json_bytes(); let delta_data = DeltaBuilder::new().insert(&json).build().json_bytes();
let revision = Revision::initial_revision(user_id, folder_id.as_ref(), delta_data); let revision = Revision::initial_revision(user_id, folder_id.as_ref(), delta_data);
let record = RevisionRecord { let record = RevisionRecord {
revision, revision,

View File

@ -10,7 +10,7 @@ use flowy_sync::{
}, },
}; };
use lib_infra::future::{BoxResultFuture, FutureResult}; use lib_infra::future::{BoxResultFuture, FutureResult};
use lib_ot::core::{OperationTransform, PhantomAttributes, TextDelta}; use lib_ot::core::{Delta, EmptyAttributes, OperationTransform};
use parking_lot::RwLock; use parking_lot::RwLock;
use std::{sync::Arc, time::Duration}; use std::{sync::Arc, time::Duration};
@ -24,12 +24,8 @@ pub(crate) async fn make_folder_ws_manager(
) -> Arc<RevisionWebSocketManager> { ) -> Arc<RevisionWebSocketManager> {
let ws_data_provider = Arc::new(WSDataProvider::new(folder_id, Arc::new(rev_manager.clone()))); let ws_data_provider = Arc::new(WSDataProvider::new(folder_id, Arc::new(rev_manager.clone())));
let resolver = Arc::new(FolderConflictResolver { folder_pad }); let resolver = Arc::new(FolderConflictResolver { folder_pad });
let conflict_controller = ConflictController::<PhantomAttributes>::new( let conflict_controller =
user_id, ConflictController::<EmptyAttributes>::new(user_id, resolver, Arc::new(ws_data_provider.clone()), rev_manager);
resolver,
Arc::new(ws_data_provider.clone()),
rev_manager,
);
let ws_data_stream = Arc::new(FolderRevisionWSDataStream::new(conflict_controller)); let ws_data_stream = Arc::new(FolderRevisionWSDataStream::new(conflict_controller));
let ws_data_sink = Arc::new(FolderWSDataSink(ws_data_provider)); let ws_data_sink = Arc::new(FolderWSDataSink(ws_data_provider));
let ping_duration = Duration::from_millis(FOLDER_SYNC_INTERVAL_IN_MILLIS); let ping_duration = Duration::from_millis(FOLDER_SYNC_INTERVAL_IN_MILLIS);
@ -55,8 +51,8 @@ struct FolderConflictResolver {
folder_pad: Arc<RwLock<FolderPad>>, folder_pad: Arc<RwLock<FolderPad>>,
} }
impl ConflictResolver<PhantomAttributes> for FolderConflictResolver { impl ConflictResolver<EmptyAttributes> for FolderConflictResolver {
fn compose_delta(&self, delta: TextDelta) -> BoxResultFuture<DeltaMD5, FlowyError> { fn compose_delta(&self, delta: Delta) -> BoxResultFuture<DeltaMD5, FlowyError> {
let folder_pad = self.folder_pad.clone(); let folder_pad = self.folder_pad.clone();
Box::pin(async move { Box::pin(async move {
let md5 = folder_pad.write().compose_remote_delta(delta)?; let md5 = folder_pad.write().compose_remote_delta(delta)?;
@ -64,12 +60,12 @@ impl ConflictResolver<PhantomAttributes> for FolderConflictResolver {
}) })
} }
fn transform_delta(&self, delta: TextDelta) -> BoxResultFuture<TransformDeltas<PhantomAttributes>, FlowyError> { fn transform_delta(&self, delta: Delta) -> BoxResultFuture<TransformDeltas<EmptyAttributes>, FlowyError> {
let folder_pad = self.folder_pad.clone(); let folder_pad = self.folder_pad.clone();
Box::pin(async move { Box::pin(async move {
let read_guard = folder_pad.read(); let read_guard = folder_pad.read();
let mut server_prime: Option<TextDelta> = None; let mut server_prime: Option<Delta> = None;
let client_prime: TextDelta; let client_prime: Delta;
if read_guard.is_empty() { if read_guard.is_empty() {
// Do nothing // Do nothing
client_prime = delta; client_prime = delta;
@ -86,7 +82,7 @@ impl ConflictResolver<PhantomAttributes> for FolderConflictResolver {
}) })
} }
fn reset_delta(&self, delta: TextDelta) -> BoxResultFuture<DeltaMD5, FlowyError> { fn reset_delta(&self, delta: Delta) -> BoxResultFuture<DeltaMD5, FlowyError> {
let folder_pad = self.folder_pad.clone(); let folder_pad = self.folder_pad.clone();
Box::pin(async move { Box::pin(async move {
let md5 = folder_pad.write().reset_folder(delta)?; let md5 = folder_pad.write().reset_folder(delta)?;

View File

@ -536,14 +536,14 @@ pub fn make_grid_setting(view_pad: &GridViewRevisionPad, field_revs: &[Arc<Field
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use lib_ot::core::TextDelta; use lib_ot::core::Delta;
#[test] #[test]
fn test() { fn test() {
let s1 = r#"[{"insert":"{\"view_id\":\"fTURELffPr\",\"grid_id\":\"fTURELffPr\",\"layout\":0,\"filters\":[],\"groups\":[]}"}]"#; let s1 = r#"[{"insert":"{\"view_id\":\"fTURELffPr\",\"grid_id\":\"fTURELffPr\",\"layout\":0,\"filters\":[],\"groups\":[]}"}]"#;
let _delta_1 = TextDelta::from_json(s1).unwrap(); let _delta_1 = Delta::from_json(s1).unwrap();
let s2 = r#"[{"retain":195},{"insert":"{\\\"group_id\\\":\\\"wD9i\\\",\\\"visible\\\":true},{\\\"group_id\\\":\\\"xZtv\\\",\\\"visible\\\":true},{\\\"group_id\\\":\\\"tFV2\\\",\\\"visible\\\":true}"},{"retain":10}]"#; let s2 = r#"[{"retain":195},{"insert":"{\\\"group_id\\\":\\\"wD9i\\\",\\\"visible\\\":true},{\\\"group_id\\\":\\\"xZtv\\\",\\\"visible\\\":true},{\\\"group_id\\\":\\\"tFV2\\\",\\\"visible\\\":true}"},{"retain":10}]"#;
let _delta_2 = TextDelta::from_json(s2).unwrap(); let _delta_2 = Delta::from_json(s2).unwrap();
} }
} }

View File

@ -3,7 +3,7 @@ use crate::{RevisionLoader, RevisionPersistence};
use flowy_database::kv::KV; use flowy_database::kv::KV;
use flowy_error::{FlowyError, FlowyResult}; use flowy_error::{FlowyError, FlowyResult};
use flowy_sync::entities::revision::Revision; use flowy_sync::entities::revision::Revision;
use lib_ot::core::TextDeltaBuilder; use lib_ot::core::DeltaBuilder;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::str::FromStr; use std::str::FromStr;
use std::sync::Arc; use std::sync::Arc;
@ -70,7 +70,7 @@ where
.await?; .await?;
let s = self.target.target_reset_rev_str(revisions)?; let s = self.target.target_reset_rev_str(revisions)?;
let delta_data = TextDeltaBuilder::new().insert(&s).build().json_bytes(); let delta_data = DeltaBuilder::new().insert(&s).build().json_bytes();
let revision = Revision::initial_revision(&self.user_id, self.target.target_id(), delta_data); let revision = Revision::initial_revision(&self.user_id, self.target.target_id(), delta_data);
let record = RevisionRecord::new(revision); let record = RevisionRecord::new(revision);

View File

@ -9,8 +9,8 @@ use flowy_sync::{
util::make_delta_from_revisions, util::make_delta_from_revisions,
}; };
use lib_infra::future::BoxResultFuture; use lib_infra::future::BoxResultFuture;
use lib_ot::core::{Attributes, Delta, PhantomAttributes}; use lib_ot::core::{Attributes, EmptyAttributes, Operations};
use lib_ot::rich_text::TextAttributes; use lib_ot::text_delta::TextAttributes;
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use std::{convert::TryFrom, sync::Arc}; use std::{convert::TryFrom, sync::Arc};
@ -20,9 +20,9 @@ pub trait ConflictResolver<T>
where where
T: Attributes + Send + Sync, T: Attributes + Send + Sync,
{ {
fn compose_delta(&self, delta: Delta<T>) -> BoxResultFuture<DeltaMD5, FlowyError>; fn compose_delta(&self, delta: Operations<T>) -> BoxResultFuture<DeltaMD5, FlowyError>;
fn transform_delta(&self, delta: Delta<T>) -> BoxResultFuture<TransformDeltas<T>, FlowyError>; fn transform_delta(&self, delta: Operations<T>) -> BoxResultFuture<TransformDeltas<T>, FlowyError>;
fn reset_delta(&self, delta: Delta<T>) -> BoxResultFuture<DeltaMD5, FlowyError>; fn reset_delta(&self, delta: Operations<T>) -> BoxResultFuture<DeltaMD5, FlowyError>;
} }
pub trait ConflictRevisionSink: Send + Sync + 'static { pub trait ConflictRevisionSink: Send + Sync + 'static {
@ -31,7 +31,7 @@ pub trait ConflictRevisionSink: Send + Sync + 'static {
} }
pub type RichTextConflictController = ConflictController<TextAttributes>; pub type RichTextConflictController = ConflictController<TextAttributes>;
pub type PlainTextConflictController = ConflictController<PhantomAttributes>; pub type PlainTextConflictController = ConflictController<EmptyAttributes>;
pub struct ConflictController<T> pub struct ConflictController<T>
where where
@ -142,8 +142,8 @@ where
fn make_client_and_server_revision<T>( fn make_client_and_server_revision<T>(
user_id: &str, user_id: &str,
rev_manager: &Arc<RevisionManager>, rev_manager: &Arc<RevisionManager>,
client_delta: Delta<T>, client_delta: Operations<T>,
server_delta: Option<Delta<T>>, server_delta: Option<Operations<T>>,
md5: String, md5: String,
) -> (Revision, Option<Revision>) ) -> (Revision, Option<Revision>)
where where
@ -181,6 +181,6 @@ pub struct TransformDeltas<T>
where where
T: Attributes, T: Attributes,
{ {
pub client_prime: Delta<T>, pub client_prime: Operations<T>,
pub server_prime: Option<Delta<T>>, pub server_prime: Option<Operations<T>>,
} }

View File

@ -15,7 +15,7 @@ use flowy_sync::{
}; };
use lib_ot::{ use lib_ot::{
core::{Interval, Operation}, core::{Interval, Operation},
rich_text::{RichTextDelta, TextAttribute}, text_delta::{TextAttribute, TextDelta},
}; };
use lib_ws::WSConnectState; use lib_ws::WSConnectState;
use std::sync::Arc; use std::sync::Arc;
@ -149,7 +149,7 @@ impl TextBlockEditor {
#[tracing::instrument(level = "trace", skip(self, data), err)] #[tracing::instrument(level = "trace", skip(self, data), err)]
pub(crate) async fn compose_local_delta(&self, data: Bytes) -> Result<(), FlowyError> { pub(crate) async fn compose_local_delta(&self, data: Bytes) -> Result<(), FlowyError> {
let delta = RichTextDelta::from_bytes(&data)?; let delta = TextDelta::from_bytes(&data)?;
let (ret, rx) = oneshot::channel::<CollaborateResult<()>>(); let (ret, rx) = oneshot::channel::<CollaborateResult<()>>();
let msg = EditorCommand::ComposeLocalDelta { let msg = EditorCommand::ComposeLocalDelta {
delta: delta.clone(), delta: delta.clone(),
@ -195,7 +195,7 @@ impl std::ops::Drop for TextBlockEditor {
fn spawn_edit_queue( fn spawn_edit_queue(
user: Arc<dyn TextBlockUser>, user: Arc<dyn TextBlockUser>,
rev_manager: Arc<RevisionManager>, rev_manager: Arc<RevisionManager>,
delta: RichTextDelta, delta: TextDelta,
) -> EditorCommandSender { ) -> EditorCommandSender {
let (sender, receiver) = mpsc::channel(1000); let (sender, receiver) = mpsc::channel(1000);
let edit_queue = EditBlockQueue::new(user, rev_manager, delta, receiver); let edit_queue = EditBlockQueue::new(user, rev_manager, delta, receiver);
@ -214,8 +214,8 @@ fn spawn_edit_queue(
#[cfg(feature = "flowy_unit_test")] #[cfg(feature = "flowy_unit_test")]
impl TextBlockEditor { impl TextBlockEditor {
pub async fn text_block_delta(&self) -> FlowyResult<RichTextDelta> { pub async fn text_block_delta(&self) -> FlowyResult<TextDelta> {
let (ret, rx) = oneshot::channel::<CollaborateResult<RichTextDelta>>(); let (ret, rx) = oneshot::channel::<CollaborateResult<TextDelta>>();
let msg = EditorCommand::ReadDelta { ret }; let msg = EditorCommand::ReadDelta { ret };
let _ = self.edit_cmd_tx.send(msg).await; let _ = self.edit_cmd_tx.send(msg).await;
let delta = rx.await.map_err(internal_error)??; let delta = rx.await.map_err(internal_error)??;
@ -247,7 +247,7 @@ impl RevisionObjectBuilder for TextBlockInfoBuilder {
// quill-editor requires the delta should end with '\n' and only contains the // quill-editor requires the delta should end with '\n' and only contains the
// insert operation. The function, correct_delta maybe be removed in the future. // insert operation. The function, correct_delta maybe be removed in the future.
fn correct_delta(delta: &mut RichTextDelta) { fn correct_delta(delta: &mut TextDelta) {
if let Some(op) = delta.ops.last() { if let Some(op) = delta.ops.last() {
let op_data = op.get_data(); let op_data = op.get_data();
if !op_data.ends_with('\n') { if !op_data.ends_with('\n') {

View File

@ -13,7 +13,7 @@ use flowy_sync::{
use futures::stream::StreamExt; use futures::stream::StreamExt;
use lib_ot::{ use lib_ot::{
core::{Interval, OperationTransform}, core::{Interval, OperationTransform},
rich_text::{RichTextDelta, TextAttribute, TextAttributes}, text_delta::{TextAttribute, TextAttributes, TextDelta},
}; };
use std::sync::Arc; use std::sync::Arc;
use tokio::sync::{oneshot, RwLock}; use tokio::sync::{oneshot, RwLock};
@ -31,7 +31,7 @@ impl EditBlockQueue {
pub(crate) fn new( pub(crate) fn new(
user: Arc<dyn TextBlockUser>, user: Arc<dyn TextBlockUser>,
rev_manager: Arc<RevisionManager>, rev_manager: Arc<RevisionManager>,
delta: RichTextDelta, delta: TextDelta,
receiver: EditorCommandReceiver, receiver: EditorCommandReceiver,
) -> Self { ) -> Self {
let document = Arc::new(RwLock::new(ClientDocument::from_delta(delta))); let document = Arc::new(RwLock::new(ClientDocument::from_delta(delta)));
@ -91,8 +91,8 @@ impl EditBlockQueue {
EditorCommand::TransformDelta { delta, ret } => { EditorCommand::TransformDelta { delta, ret } => {
let f = || async { let f = || async {
let read_guard = self.document.read().await; let read_guard = self.document.read().await;
let mut server_prime: Option<RichTextDelta> = None; let mut server_prime: Option<TextDelta> = None;
let client_prime: RichTextDelta; let client_prime: TextDelta;
if read_guard.is_empty() { if read_guard.is_empty() {
// Do nothing // Do nothing
@ -174,7 +174,7 @@ impl EditBlockQueue {
Ok(()) Ok(())
} }
async fn save_local_delta(&self, delta: RichTextDelta, md5: String) -> Result<RevId, FlowyError> { async fn save_local_delta(&self, delta: TextDelta, md5: String) -> Result<RevId, FlowyError> {
let delta_data = delta.json_bytes(); let delta_data = delta.json_bytes();
let (base_rev_id, rev_id) = self.rev_manager.next_rev_id_pair(); let (base_rev_id, rev_id) = self.rev_manager.next_rev_id_pair();
let user_id = self.user.user_id()?; let user_id = self.user.user_id()?;
@ -203,19 +203,19 @@ pub(crate) type Ret<T> = oneshot::Sender<Result<T, CollaborateError>>;
pub(crate) enum EditorCommand { pub(crate) enum EditorCommand {
ComposeLocalDelta { ComposeLocalDelta {
delta: RichTextDelta, delta: TextDelta,
ret: Ret<()>, ret: Ret<()>,
}, },
ComposeRemoteDelta { ComposeRemoteDelta {
client_delta: RichTextDelta, client_delta: TextDelta,
ret: Ret<DeltaMD5>, ret: Ret<DeltaMD5>,
}, },
ResetDelta { ResetDelta {
delta: RichTextDelta, delta: TextDelta,
ret: Ret<DeltaMD5>, ret: Ret<DeltaMD5>,
}, },
TransformDelta { TransformDelta {
delta: RichTextDelta, delta: TextDelta,
ret: Ret<RichTextTransformDeltas>, ret: Ret<RichTextTransformDeltas>,
}, },
Insert { Insert {
@ -254,7 +254,7 @@ pub(crate) enum EditorCommand {
}, },
#[allow(dead_code)] #[allow(dead_code)]
ReadDelta { ReadDelta {
ret: Ret<RichTextDelta>, ret: Ret<TextDelta>,
}, },
} }

View File

@ -10,8 +10,8 @@ use flowy_sync::{
errors::CollaborateResult, errors::CollaborateResult,
}; };
use lib_infra::future::{BoxResultFuture, FutureResult}; use lib_infra::future::{BoxResultFuture, FutureResult};
use lib_ot::rich_text::RichTextDelta; use lib_ot::text_delta::TextAttributes;
use lib_ot::rich_text::TextAttributes; use lib_ot::text_delta::TextDelta;
use lib_ws::WSConnectState; use lib_ws::WSConnectState;
use std::{sync::Arc, time::Duration}; use std::{sync::Arc, time::Duration};
use tokio::sync::{ use tokio::sync::{
@ -112,7 +112,7 @@ struct TextBlockConflictResolver {
} }
impl ConflictResolver<TextAttributes> for TextBlockConflictResolver { impl ConflictResolver<TextAttributes> for TextBlockConflictResolver {
fn compose_delta(&self, delta: RichTextDelta) -> BoxResultFuture<DeltaMD5, FlowyError> { fn compose_delta(&self, delta: TextDelta) -> BoxResultFuture<DeltaMD5, FlowyError> {
let tx = self.edit_cmd_tx.clone(); let tx = self.edit_cmd_tx.clone();
Box::pin(async move { Box::pin(async move {
let (ret, rx) = oneshot::channel(); let (ret, rx) = oneshot::channel();
@ -131,7 +131,7 @@ impl ConflictResolver<TextAttributes> for TextBlockConflictResolver {
fn transform_delta( fn transform_delta(
&self, &self,
delta: RichTextDelta, delta: TextDelta,
) -> BoxResultFuture<flowy_revision::RichTextTransformDeltas, FlowyError> { ) -> BoxResultFuture<flowy_revision::RichTextTransformDeltas, FlowyError> {
let tx = self.edit_cmd_tx.clone(); let tx = self.edit_cmd_tx.clone();
Box::pin(async move { Box::pin(async move {
@ -146,7 +146,7 @@ impl ConflictResolver<TextAttributes> for TextBlockConflictResolver {
}) })
} }
fn reset_delta(&self, delta: RichTextDelta) -> BoxResultFuture<DeltaMD5, FlowyError> { fn reset_delta(&self, delta: TextDelta) -> BoxResultFuture<DeltaMD5, FlowyError> {
let tx = self.edit_cmd_tx.clone(); let tx = self.edit_cmd_tx.clone();
Box::pin(async move { Box::pin(async move {
let (ret, rx) = oneshot::channel(); let (ret, rx) = oneshot::channel();

View File

@ -2,7 +2,7 @@ use flowy_revision::disk::RevisionState;
use flowy_test::{helper::ViewTest, FlowySDKTest}; use flowy_test::{helper::ViewTest, FlowySDKTest};
use flowy_text_block::editor::TextBlockEditor; use flowy_text_block::editor::TextBlockEditor;
use flowy_text_block::TEXT_BLOCK_SYNC_INTERVAL_IN_MILLIS; use flowy_text_block::TEXT_BLOCK_SYNC_INTERVAL_IN_MILLIS;
use lib_ot::{core::Interval, rich_text::RichTextDelta}; use lib_ot::{core::Interval, text_delta::TextDelta};
use std::sync::Arc; use std::sync::Arc;
use tokio::time::{sleep, Duration}; use tokio::time::{sleep, Duration};
@ -71,7 +71,7 @@ impl TextBlockEditorTest {
assert_eq!(next_revision.rev_id, rev_id.unwrap()); assert_eq!(next_revision.rev_id, rev_id.unwrap());
} }
EditorScript::AssertJson(expected) => { EditorScript::AssertJson(expected) => {
let expected_delta: RichTextDelta = serde_json::from_str(expected).unwrap(); let expected_delta: TextDelta = serde_json::from_str(expected).unwrap();
let delta = self.editor.text_block_delta().await.unwrap(); let delta = self.editor.text_block_delta().await.unwrap();
if expected_delta != delta { if expected_delta != delta {
eprintln!("✅ expect: {}", expected,); eprintln!("✅ expect: {}", expected,);

View File

@ -3,7 +3,7 @@ use crate::editor::{TestBuilder, TestOp::*};
use flowy_sync::client_document::{NewlineDoc, PlainDoc}; use flowy_sync::client_document::{NewlineDoc, PlainDoc};
use lib_ot::core::{Interval, OperationTransform, NEW_LINE, WHITESPACE, OTString}; use lib_ot::core::{Interval, OperationTransform, NEW_LINE, WHITESPACE, OTString};
use unicode_segmentation::UnicodeSegmentation; use unicode_segmentation::UnicodeSegmentation;
use lib_ot::rich_text::RichTextDelta; use lib_ot::text_delta::TextDelta;
#[test] #[test]
fn attributes_bold_added() { fn attributes_bold_added() {
@ -762,12 +762,12 @@ fn attributes_preserve_list_format_on_merge() {
#[test] #[test]
fn delta_compose() { fn delta_compose() {
let mut delta = RichTextDelta::from_json(r#"[{"insert":"\n"}]"#).unwrap(); let mut delta = TextDelta::from_json(r#"[{"insert":"\n"}]"#).unwrap();
let deltas = vec![ let deltas = vec![
RichTextDelta::from_json(r#"[{"retain":1,"attributes":{"list":"unchecked"}}]"#).unwrap(), TextDelta::from_json(r#"[{"retain":1,"attributes":{"list":"unchecked"}}]"#).unwrap(),
RichTextDelta::from_json(r#"[{"insert":"a"}]"#).unwrap(), TextDelta::from_json(r#"[{"insert":"a"}]"#).unwrap(),
RichTextDelta::from_json(r#"[{"retain":1},{"insert":"\n","attributes":{"list":"unchecked"}}]"#).unwrap(), TextDelta::from_json(r#"[{"retain":1},{"insert":"\n","attributes":{"list":"unchecked"}}]"#).unwrap(),
RichTextDelta::from_json(r#"[{"retain":2},{"retain":1,"attributes":{"list":""}}]"#).unwrap(), TextDelta::from_json(r#"[{"retain":2},{"retain":1,"attributes":{"list":""}}]"#).unwrap(),
]; ];
for d in deltas { for d in deltas {

View File

@ -8,7 +8,7 @@ use derive_more::Display;
use flowy_sync::client_document::{ClientDocument, InitialDocumentText}; use flowy_sync::client_document::{ClientDocument, InitialDocumentText};
use lib_ot::{ use lib_ot::{
core::*, core::*,
rich_text::{RichTextDelta, TextAttribute, TextAttributes}, text_delta::{TextAttribute, TextAttributes, TextDelta},
}; };
use rand::{prelude::*, Rng as WrappedRng}; use rand::{prelude::*, Rng as WrappedRng};
use std::{sync::Once, time::Duration}; use std::{sync::Once, time::Duration};
@ -83,8 +83,8 @@ pub enum TestOp {
pub struct TestBuilder { pub struct TestBuilder {
documents: Vec<ClientDocument>, documents: Vec<ClientDocument>,
deltas: Vec<Option<RichTextDelta>>, deltas: Vec<Option<TextDelta>>,
primes: Vec<Option<RichTextDelta>>, primes: Vec<Option<TextDelta>>,
} }
impl TestBuilder { impl TestBuilder {
@ -227,8 +227,8 @@ impl TestBuilder {
TestOp::AssertDocJson(delta_i, expected) => { TestOp::AssertDocJson(delta_i, expected) => {
let delta_json = self.documents[*delta_i].delta_str(); let delta_json = self.documents[*delta_i].delta_str();
let expected_delta: RichTextDelta = serde_json::from_str(expected).unwrap(); let expected_delta: TextDelta = serde_json::from_str(expected).unwrap();
let target_delta: RichTextDelta = serde_json::from_str(&delta_json).unwrap(); let target_delta: TextDelta = 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,);
@ -239,8 +239,8 @@ impl TestBuilder {
TestOp::AssertPrimeJson(doc_i, expected) => { TestOp::AssertPrimeJson(doc_i, expected) => {
let prime_json = self.primes[*doc_i].as_ref().unwrap().json_str(); let prime_json = self.primes[*doc_i].as_ref().unwrap().json_str();
let expected_prime: RichTextDelta = serde_json::from_str(expected).unwrap(); let expected_prime: TextDelta = serde_json::from_str(expected).unwrap();
let target_prime: RichTextDelta = serde_json::from_str(&prime_json).unwrap(); let target_prime: TextDelta = 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,);
@ -298,8 +298,8 @@ impl Rng {
.collect() .collect()
} }
pub fn gen_delta(&mut self, s: &str) -> RichTextDelta { pub fn gen_delta(&mut self, s: &str) -> TextDelta {
let mut delta = RichTextDelta::default(); let mut delta = TextDelta::default();
let s = OTString::from(s); let s = OTString::from(s);
loop { loop {
let left = s.utf16_len() - delta.utf16_base_len; let left = s.utf16_len() - delta.utf16_base_len;

View File

@ -1,11 +1,11 @@
#![allow(clippy::all)] #![allow(clippy::all)]
use crate::editor::{Rng, TestBuilder, TestOp::*}; use crate::editor::{Rng, TestBuilder, TestOp::*};
use flowy_sync::client_document::{NewlineDoc, PlainDoc}; use flowy_sync::client_document::{NewlineDoc, PlainDoc};
use lib_ot::rich_text::RichTextDeltaBuilder; use lib_ot::text_delta::TextDeltaBuilder;
use lib_ot::{ use lib_ot::{
core::Interval, core::Interval,
core::*, core::*,
rich_text::{AttributeBuilder, RichTextDelta, TextAttribute, TextAttributes}, text_delta::{AttributeBuilder, TextAttribute, TextAttributes, TextDelta},
}; };
#[test] #[test]
@ -41,15 +41,15 @@ fn attributes_insert_text_at_middle() {
#[test] #[test]
fn delta_get_ops_in_interval_1() { fn delta_get_ops_in_interval_1() {
let operations = OperationsBuilder::new().insert("123").insert("4").build(); let operations = OperationsBuilder::new().insert("123").insert("4").build();
let delta = RichTextDeltaBuilder::from_operations(operations); let delta = TextDeltaBuilder::from_operations(operations);
let mut iterator = DeltaIterator::from_interval(&delta, Interval::new(0, 4)); let mut iterator = OperationIterator::from_interval(&delta, Interval::new(0, 4));
assert_eq!(iterator.ops(), delta.ops); assert_eq!(iterator.ops(), delta.ops);
} }
#[test] #[test]
fn delta_get_ops_in_interval_2() { fn delta_get_ops_in_interval_2() {
let mut delta = RichTextDelta::default(); let mut delta = TextDelta::default();
let insert_a = Operation::insert("123"); let insert_a = Operation::insert("123");
let insert_b = Operation::insert("4"); let insert_b = Operation::insert("4");
let insert_c = Operation::insert("5"); let insert_c = Operation::insert("5");
@ -61,50 +61,50 @@ fn delta_get_ops_in_interval_2() {
delta.add(insert_c.clone()); delta.add(insert_c.clone());
assert_eq!( assert_eq!(
DeltaIterator::from_interval(&delta, Interval::new(0, 2)).ops(), OperationIterator::from_interval(&delta, Interval::new(0, 2)).ops(),
vec![Operation::insert("12")] vec![Operation::insert("12")]
); );
assert_eq!( assert_eq!(
DeltaIterator::from_interval(&delta, Interval::new(1, 3)).ops(), OperationIterator::from_interval(&delta, Interval::new(1, 3)).ops(),
vec![Operation::insert("23")] vec![Operation::insert("23")]
); );
assert_eq!( assert_eq!(
DeltaIterator::from_interval(&delta, Interval::new(0, 3)).ops(), OperationIterator::from_interval(&delta, Interval::new(0, 3)).ops(),
vec![insert_a.clone()] vec![insert_a.clone()]
); );
assert_eq!( assert_eq!(
DeltaIterator::from_interval(&delta, Interval::new(0, 4)).ops(), OperationIterator::from_interval(&delta, Interval::new(0, 4)).ops(),
vec![insert_a.clone(), Operation::retain(1)] vec![insert_a.clone(), Operation::retain(1)]
); );
assert_eq!( assert_eq!(
DeltaIterator::from_interval(&delta, Interval::new(0, 6)).ops(), OperationIterator::from_interval(&delta, Interval::new(0, 6)).ops(),
vec![insert_a.clone(), retain_a.clone()] vec![insert_a.clone(), retain_a.clone()]
); );
assert_eq!( assert_eq!(
DeltaIterator::from_interval(&delta, Interval::new(0, 7)).ops(), OperationIterator::from_interval(&delta, Interval::new(0, 7)).ops(),
vec![insert_a.clone(), retain_a.clone(), insert_b.clone()] vec![insert_a.clone(), retain_a.clone(), insert_b.clone()]
); );
} }
#[test] #[test]
fn delta_get_ops_in_interval_3() { fn delta_get_ops_in_interval_3() {
let mut delta = RichTextDelta::default(); let mut delta = TextDelta::default();
let insert_a = Operation::insert("123456"); let insert_a = Operation::insert("123456");
delta.add(insert_a.clone()); delta.add(insert_a.clone());
assert_eq!( assert_eq!(
DeltaIterator::from_interval(&delta, Interval::new(3, 5)).ops(), OperationIterator::from_interval(&delta, Interval::new(3, 5)).ops(),
vec![Operation::insert("45")] vec![Operation::insert("45")]
); );
} }
#[test] #[test]
fn delta_get_ops_in_interval_4() { fn delta_get_ops_in_interval_4() {
let mut delta = RichTextDelta::default(); let mut delta = TextDelta::default();
let insert_a = Operation::insert("12"); let insert_a = Operation::insert("12");
let insert_b = Operation::insert("34"); let insert_b = Operation::insert("34");
let insert_c = Operation::insert("56"); let insert_c = Operation::insert("56");
@ -114,33 +114,33 @@ fn delta_get_ops_in_interval_4() {
delta.ops.push(insert_c.clone()); delta.ops.push(insert_c.clone());
assert_eq!( assert_eq!(
DeltaIterator::from_interval(&delta, Interval::new(0, 2)).ops(), OperationIterator::from_interval(&delta, Interval::new(0, 2)).ops(),
vec![insert_a] vec![insert_a]
); );
assert_eq!( assert_eq!(
DeltaIterator::from_interval(&delta, Interval::new(2, 4)).ops(), OperationIterator::from_interval(&delta, Interval::new(2, 4)).ops(),
vec![insert_b] vec![insert_b]
); );
assert_eq!( assert_eq!(
DeltaIterator::from_interval(&delta, Interval::new(4, 6)).ops(), OperationIterator::from_interval(&delta, Interval::new(4, 6)).ops(),
vec![insert_c] vec![insert_c]
); );
assert_eq!( assert_eq!(
DeltaIterator::from_interval(&delta, Interval::new(2, 5)).ops(), OperationIterator::from_interval(&delta, Interval::new(2, 5)).ops(),
vec![Operation::insert("34"), Operation::insert("5")] vec![Operation::insert("34"), Operation::insert("5")]
); );
} }
#[test] #[test]
fn delta_get_ops_in_interval_5() { fn delta_get_ops_in_interval_5() {
let mut delta = RichTextDelta::default(); let mut delta = TextDelta::default();
let insert_a = Operation::insert("123456"); let insert_a = Operation::insert("123456");
let insert_b = Operation::insert("789"); let insert_b = Operation::insert("789");
delta.ops.push(insert_a.clone()); delta.ops.push(insert_a.clone());
delta.ops.push(insert_b.clone()); delta.ops.push(insert_b.clone());
assert_eq!( assert_eq!(
DeltaIterator::from_interval(&delta, Interval::new(4, 8)).ops(), OperationIterator::from_interval(&delta, Interval::new(4, 8)).ops(),
vec![Operation::insert("56"), Operation::insert("78")] vec![Operation::insert("56"), Operation::insert("78")]
); );
@ -152,29 +152,29 @@ 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 = RichTextDelta::default(); let mut delta = TextDelta::default();
let insert_a = Operation::insert("12345678"); let insert_a = Operation::insert("12345678");
delta.add(insert_a.clone()); delta.add(insert_a.clone());
assert_eq!( assert_eq!(
DeltaIterator::from_interval(&delta, Interval::new(4, 6)).ops(), OperationIterator::from_interval(&delta, Interval::new(4, 6)).ops(),
vec![Operation::insert("56")] vec![Operation::insert("56")]
); );
} }
#[test] #[test]
fn delta_get_ops_in_interval_7() { fn delta_get_ops_in_interval_7() {
let mut delta = RichTextDelta::default(); let mut delta = TextDelta::default();
let insert_a = Operation::insert("12345"); let insert_a = Operation::insert("12345");
let retain_a = Operation::retain(3); let retain_a = Operation::retain(3);
delta.add(insert_a.clone()); delta.add(insert_a.clone());
delta.add(retain_a.clone()); delta.add(retain_a.clone());
let mut iter_1 = DeltaIterator::from_offset(&delta, 2); let mut iter_1 = OperationIterator::from_offset(&delta, 2);
assert_eq!(iter_1.next_op().unwrap(), Operation::insert("345")); assert_eq!(iter_1.next_op().unwrap(), Operation::insert("345"));
assert_eq!(iter_1.next_op().unwrap(), Operation::retain(3)); assert_eq!(iter_1.next_op().unwrap(), Operation::retain(3));
let mut iter_2 = DeltaIterator::new(&delta); let mut iter_2 = OperationIterator::new(&delta);
assert_eq!(iter_2.next_op_with_len(2).unwrap(), Operation::insert("12")); assert_eq!(iter_2.next_op_with_len(2).unwrap(), Operation::insert("12"));
assert_eq!(iter_2.next_op().unwrap(), Operation::insert("345")); assert_eq!(iter_2.next_op().unwrap(), Operation::insert("345"));
@ -183,29 +183,29 @@ fn delta_get_ops_in_interval_7() {
#[test] #[test]
fn delta_op_seek() { fn delta_op_seek() {
let mut delta = RichTextDelta::default(); let mut delta = TextDelta::default();
let insert_a = Operation::insert("12345"); let insert_a = Operation::insert("12345");
let retain_a = Operation::retain(3); let retain_a = Operation::retain(3);
delta.add(insert_a.clone()); delta.add(insert_a.clone());
delta.add(retain_a.clone()); delta.add(retain_a.clone());
let mut iter = DeltaIterator::new(&delta); let mut iter = OperationIterator::new(&delta);
iter.seek::<OpMetric>(1); iter.seek::<OpMetric>(1);
assert_eq!(iter.next_op().unwrap(), retain_a); assert_eq!(iter.next_op().unwrap(), retain_a);
} }
#[test] #[test]
fn delta_utf16_code_unit_seek() { fn delta_utf16_code_unit_seek() {
let mut delta = RichTextDelta::default(); let mut delta = TextDelta::default();
delta.add(Operation::insert("12345")); delta.add(Operation::insert("12345"));
let mut iter = DeltaIterator::new(&delta); let mut iter = OperationIterator::new(&delta);
iter.seek::<Utf16CodeUnitMetric>(3); iter.seek::<Utf16CodeUnitMetric>(3);
assert_eq!(iter.next_op_with_len(2).unwrap(), Operation::insert("45")); assert_eq!(iter.next_op_with_len(2).unwrap(), Operation::insert("45"));
} }
#[test] #[test]
fn delta_utf16_code_unit_seek_with_attributes() { fn delta_utf16_code_unit_seek_with_attributes() {
let mut delta = RichTextDelta::default(); let mut delta = TextDelta::default();
let attributes = AttributeBuilder::new() let attributes = AttributeBuilder::new()
.add_attr(TextAttribute::Bold(true)) .add_attr(TextAttribute::Bold(true))
.add_attr(TextAttribute::Italic(true)) .add_attr(TextAttribute::Italic(true))
@ -214,7 +214,7 @@ fn delta_utf16_code_unit_seek_with_attributes() {
delta.add(Operation::insert_with_attributes("1234", attributes.clone())); delta.add(Operation::insert_with_attributes("1234", attributes.clone()));
delta.add(Operation::insert("\n")); delta.add(Operation::insert("\n"));
let mut iter = DeltaIterator::new(&delta); let mut iter = OperationIterator::new(&delta);
iter.seek::<Utf16CodeUnitMetric>(0); iter.seek::<Utf16CodeUnitMetric>(0);
assert_eq!( assert_eq!(
@ -225,9 +225,9 @@ fn delta_utf16_code_unit_seek_with_attributes() {
#[test] #[test]
fn delta_next_op_len() { fn delta_next_op_len() {
let mut delta = RichTextDelta::default(); let mut delta = TextDelta::default();
delta.add(Operation::insert("12345")); delta.add(Operation::insert("12345"));
let mut iter = DeltaIterator::new(&delta); let mut iter = OperationIterator::new(&delta);
assert_eq!(iter.next_op_with_len(2).unwrap(), Operation::insert("12")); assert_eq!(iter.next_op_with_len(2).unwrap(), Operation::insert("12"));
assert_eq!(iter.next_op_with_len(2).unwrap(), Operation::insert("34")); assert_eq!(iter.next_op_with_len(2).unwrap(), Operation::insert("34"));
assert_eq!(iter.next_op_with_len(2).unwrap(), Operation::insert("5")); assert_eq!(iter.next_op_with_len(2).unwrap(), Operation::insert("5"));
@ -236,28 +236,28 @@ fn delta_next_op_len() {
#[test] #[test]
fn delta_next_op_len_with_chinese() { fn delta_next_op_len_with_chinese() {
let mut delta = RichTextDelta::default(); let mut delta = TextDelta::default();
delta.add(Operation::insert("你好")); delta.add(Operation::insert("你好"));
let mut iter = DeltaIterator::new(&delta); let mut iter = OperationIterator::new(&delta);
assert_eq!(iter.next_op_len().unwrap(), 2); assert_eq!(iter.next_op_len().unwrap(), 2);
assert_eq!(iter.next_op_with_len(2).unwrap(), Operation::insert("你好")); assert_eq!(iter.next_op_with_len(2).unwrap(), Operation::insert("你好"));
} }
#[test] #[test]
fn delta_next_op_len_with_english() { fn delta_next_op_len_with_english() {
let mut delta = RichTextDelta::default(); let mut delta = TextDelta::default();
delta.add(Operation::insert("ab")); delta.add(Operation::insert("ab"));
let mut iter = DeltaIterator::new(&delta); let mut iter = OperationIterator::new(&delta);
assert_eq!(iter.next_op_len().unwrap(), 2); assert_eq!(iter.next_op_len().unwrap(), 2);
assert_eq!(iter.next_op_with_len(2).unwrap(), Operation::insert("ab")); assert_eq!(iter.next_op_with_len(2).unwrap(), Operation::insert("ab"));
} }
#[test] #[test]
fn delta_next_op_len_after_seek() { fn delta_next_op_len_after_seek() {
let mut delta = RichTextDelta::default(); let mut delta = TextDelta::default();
delta.add(Operation::insert("12345")); delta.add(Operation::insert("12345"));
let mut iter = DeltaIterator::new(&delta); let mut iter = OperationIterator::new(&delta);
assert_eq!(iter.next_op_len().unwrap(), 5); assert_eq!(iter.next_op_len().unwrap(), 5);
iter.seek::<Utf16CodeUnitMetric>(3); iter.seek::<Utf16CodeUnitMetric>(3);
assert_eq!(iter.next_op_len().unwrap(), 2); assert_eq!(iter.next_op_len().unwrap(), 2);
@ -268,9 +268,9 @@ fn delta_next_op_len_after_seek() {
#[test] #[test]
fn delta_next_op_len_none() { fn delta_next_op_len_none() {
let mut delta = RichTextDelta::default(); let mut delta = TextDelta::default();
delta.add(Operation::insert("12345")); delta.add(Operation::insert("12345"));
let mut iter = DeltaIterator::new(&delta); let mut iter = OperationIterator::new(&delta);
assert_eq!(iter.next_op_len().unwrap(), 5); assert_eq!(iter.next_op_len().unwrap(), 5);
assert_eq!(iter.next_op_with_len(5).unwrap(), Operation::insert("12345")); assert_eq!(iter.next_op_with_len(5).unwrap(), Operation::insert("12345"));
@ -279,21 +279,21 @@ fn delta_next_op_len_none() {
#[test] #[test]
fn delta_next_op_with_len_zero() { fn delta_next_op_with_len_zero() {
let mut delta = RichTextDelta::default(); let mut delta = TextDelta::default();
delta.add(Operation::insert("12345")); delta.add(Operation::insert("12345"));
let mut iter = DeltaIterator::new(&delta); let mut iter = OperationIterator::new(&delta);
assert_eq!(iter.next_op_with_len(0), None,); assert_eq!(iter.next_op_with_len(0), None,);
assert_eq!(iter.next_op_len().unwrap(), 5); assert_eq!(iter.next_op_len().unwrap(), 5);
} }
#[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 = RichTextDelta::default(); let mut delta = TextDelta::default();
delta.add(Operation::insert("12345")); delta.add(Operation::insert("12345"));
delta.add(Operation::retain(1)); delta.add(Operation::retain(1));
delta.add(Operation::insert("678")); delta.add(Operation::insert("678"));
let mut iter = DeltaIterator::new(&delta); let mut iter = OperationIterator::new(&delta);
iter.seek::<Utf16CodeUnitMetric>(4); iter.seek::<Utf16CodeUnitMetric>(4);
assert_eq!(iter.next_op_len().unwrap(), 1); assert_eq!(iter.next_op_len().unwrap(), 1);
assert_eq!(iter.next_op_with_len(2).unwrap(), Operation::retain(1)); assert_eq!(iter.next_op_with_len(2).unwrap(), Operation::retain(1));
@ -301,7 +301,7 @@ fn delta_next_op_with_len_cross_op_return_last() {
#[test] #[test]
fn lengths() { fn lengths() {
let mut delta = RichTextDelta::default(); let mut delta = TextDelta::default();
assert_eq!(delta.utf16_base_len, 0); assert_eq!(delta.utf16_base_len, 0);
assert_eq!(delta.utf16_target_len, 0); assert_eq!(delta.utf16_target_len, 0);
delta.retain(5, TextAttributes::default()); delta.retain(5, TextAttributes::default());
@ -319,7 +319,7 @@ fn lengths() {
} }
#[test] #[test]
fn sequence() { fn sequence() {
let mut delta = RichTextDelta::default(); let mut delta = TextDelta::default();
delta.retain(5, TextAttributes::default()); delta.retain(5, TextAttributes::default());
delta.retain(0, TextAttributes::default()); delta.retain(0, TextAttributes::default());
delta.insert("appflowy", TextAttributes::default()); delta.insert("appflowy", TextAttributes::default());
@ -342,8 +342,8 @@ fn apply_1000() {
#[test] #[test]
fn apply_test() { fn apply_test() {
let s = "hello"; let s = "hello";
let delta_a = TextDeltaBuilder::new().insert(s).build(); let delta_a = DeltaBuilder::new().insert(s).build();
let delta_b = TextDeltaBuilder::new().retain(s.len()).insert(", AppFlowy").build(); let delta_b = DeltaBuilder::new().retain(s.len()).insert(", AppFlowy").build();
let after_a = delta_a.content().unwrap(); let after_a = delta_a.content().unwrap();
let after_b = delta_b.apply(&after_a).unwrap(); let after_b = delta_b.apply(&after_a).unwrap();
@ -352,7 +352,7 @@ fn apply_test() {
#[test] #[test]
fn base_len_test() { fn base_len_test() {
let mut delta_a = RichTextDelta::default(); let mut delta_a = TextDelta::default();
delta_a.insert("a", TextAttributes::default()); delta_a.insert("a", TextAttributes::default());
delta_a.insert("b", TextAttributes::default()); delta_a.insert("b", TextAttributes::default());
delta_a.insert("c", TextAttributes::default()); delta_a.insert("c", TextAttributes::default());
@ -381,7 +381,7 @@ fn invert() {
#[test] #[test]
fn invert_test() { fn invert_test() {
let s = "hello world"; let s = "hello world";
let delta = TextDeltaBuilder::new().insert(s).build(); let delta = DeltaBuilder::new().insert(s).build();
let invert_delta = delta.invert_str(""); let invert_delta = delta.invert_str("");
assert_eq!(delta.utf16_base_len, invert_delta.utf16_target_len); assert_eq!(delta.utf16_base_len, invert_delta.utf16_target_len);
assert_eq!(delta.utf16_target_len, invert_delta.utf16_base_len); assert_eq!(delta.utf16_target_len, invert_delta.utf16_base_len);
@ -391,7 +391,7 @@ fn invert_test() {
#[test] #[test]
fn empty_ops() { fn empty_ops() {
let mut delta = RichTextDelta::default(); let mut delta = TextDelta::default();
delta.retain(0, TextAttributes::default()); delta.retain(0, TextAttributes::default());
delta.insert("", TextAttributes::default()); delta.insert("", TextAttributes::default());
delta.delete(0); delta.delete(0);
@ -399,12 +399,12 @@ fn empty_ops() {
} }
#[test] #[test]
fn eq() { fn eq() {
let mut delta_a = RichTextDelta::default(); let mut delta_a = TextDelta::default();
delta_a.delete(1); delta_a.delete(1);
delta_a.insert("lo", TextAttributes::default()); delta_a.insert("lo", TextAttributes::default());
delta_a.retain(2, TextAttributes::default()); delta_a.retain(2, TextAttributes::default());
delta_a.retain(3, TextAttributes::default()); delta_a.retain(3, TextAttributes::default());
let mut delta_b = RichTextDelta::default(); let mut delta_b = TextDelta::default();
delta_b.delete(1); delta_b.delete(1);
delta_b.insert("l", TextAttributes::default()); delta_b.insert("l", TextAttributes::default());
delta_b.insert("o", TextAttributes::default()); delta_b.insert("o", TextAttributes::default());
@ -416,7 +416,7 @@ fn eq() {
} }
#[test] #[test]
fn ops_merging() { fn ops_merging() {
let mut delta = RichTextDelta::default(); let mut delta = TextDelta::default();
assert_eq!(delta.ops.len(), 0); assert_eq!(delta.ops.len(), 0);
delta.retain(2, TextAttributes::default()); delta.retain(2, TextAttributes::default());
assert_eq!(delta.ops.len(), 1); assert_eq!(delta.ops.len(), 1);
@ -440,7 +440,7 @@ fn ops_merging() {
#[test] #[test]
fn is_noop() { fn is_noop() {
let mut delta = RichTextDelta::default(); let mut delta = TextDelta::default();
assert!(delta.is_noop()); assert!(delta.is_noop());
delta.retain(5, TextAttributes::default()); delta.retain(5, TextAttributes::default());
assert!(delta.is_noop()); assert!(delta.is_noop());
@ -488,7 +488,7 @@ fn transform_random_delta() {
#[test] #[test]
fn transform_with_two_delta() { fn transform_with_two_delta() {
let mut a = RichTextDelta::default(); let mut a = TextDelta::default();
let mut a_s = String::new(); let mut a_s = String::new();
a.insert( a.insert(
"123", "123",
@ -497,7 +497,7 @@ fn transform_with_two_delta() {
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 = RichTextDelta::default(); let mut b = TextDelta::default();
let mut b_s = String::new(); let mut b_s = String::new();
b.insert("456", TextAttributes::default()); b.insert("456", TextAttributes::default());
b_s = b.apply(&b_s).unwrap(); b_s = b.apply(&b_s).unwrap();
@ -587,10 +587,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 = RichTextDelta::default(); let mut delta = TextDelta::default();
delta.add(Operation::insert("123")); delta.add(Operation::insert("123"));
let mut change = RichTextDelta::default(); let mut change = TextDelta::default();
change.add(Operation::retain(3)); change.add(Operation::retain(3));
change.add(Operation::insert("456")); change.add(Operation::insert("456"));
let undo = change.invert(&delta); let undo = change.invert(&delta);

View File

@ -1,8 +1,8 @@
use flowy_sync::client_document::{ClientDocument, PlainDoc}; use flowy_sync::client_document::{ClientDocument, PlainDoc};
use lib_ot::rich_text::RichTextOperation; use lib_ot::text_delta::RichTextOperation;
use lib_ot::{ use lib_ot::{
core::*, core::*,
rich_text::{AttributeBuilder, RichTextDelta, TextAttribute, TextAttributeValue}, text_delta::{AttributeBuilder, TextAttribute, TextAttributeValue, TextDelta},
}; };
#[test] #[test]
@ -50,7 +50,7 @@ fn attributes_serialize_test() {
#[test] #[test]
fn delta_serialize_multi_attribute_test() { fn delta_serialize_multi_attribute_test() {
let mut delta = Delta::default(); let mut delta = Operations::default();
let attributes = AttributeBuilder::new() let attributes = AttributeBuilder::new()
.add_attr(TextAttribute::Bold(true)) .add_attr(TextAttribute::Bold(true))
@ -65,7 +65,7 @@ fn delta_serialize_multi_attribute_test() {
let json = serde_json::to_string(&delta).unwrap(); let json = serde_json::to_string(&delta).unwrap();
eprintln!("{}", json); eprintln!("{}", json);
let delta_from_json = Delta::from_json(&json).unwrap(); let delta_from_json = Operations::from_json(&json).unwrap();
assert_eq!(delta_from_json, delta); assert_eq!(delta_from_json, delta);
} }
@ -77,7 +77,7 @@ fn delta_deserialize_test() {
{"retain":2,"attributes":{"italic":"true","bold":"true"}}, {"retain":2,"attributes":{"italic":"true","bold":"true"}},
{"retain":2,"attributes":{"italic":true,"bold":true}} {"retain":2,"attributes":{"italic":true,"bold":true}}
]"#; ]"#;
let delta = RichTextDelta::from_json(json).unwrap(); let delta = TextDelta::from_json(json).unwrap();
eprintln!("{}", delta); eprintln!("{}", delta);
} }
@ -86,11 +86,13 @@ fn delta_deserialize_null_test() {
let json = r#"[ let json = r#"[
{"retain":7,"attributes":{"bold":null}} {"retain":7,"attributes":{"bold":null}}
]"#; ]"#;
let delta1 = RichTextDelta::from_json(json).unwrap(); let delta1 = TextDelta::from_json(json).unwrap();
let mut attribute = TextAttribute::Bold(true); let mut attribute = TextAttribute::Bold(true);
attribute.value = TextAttributeValue(None); attribute.value = TextAttributeValue(None);
let delta2 = DeltaBuilder::new().retain_with_attributes(7, attribute.into()).build(); let delta2 = OperationBuilder::new()
.retain_with_attributes(7, attribute.into())
.build();
assert_eq!(delta2.json_str(), r#"[{"retain":7,"attributes":{"bold":""}}]"#); assert_eq!(delta2.json_str(), r#"[{"retain":7,"attributes":{"bold":""}}]"#);
assert_eq!(delta1, delta2); assert_eq!(delta1, delta2);

View File

@ -1,8 +1,8 @@
use lib_ot::{core::DeltaBuilder, rich_text::RichTextDelta}; use lib_ot::{core::OperationBuilder, text_delta::TextDelta};
#[inline] #[inline]
pub fn initial_quill_delta() -> RichTextDelta { pub fn initial_quill_delta() -> TextDelta {
DeltaBuilder::new().insert("\n").build() OperationBuilder::new().insert("\n").build()
} }
#[inline] #[inline]
@ -11,9 +11,9 @@ pub fn initial_quill_delta_string() -> String {
} }
#[inline] #[inline]
pub fn initial_read_me() -> RichTextDelta { pub fn initial_read_me() -> TextDelta {
let json = include_str!("READ_ME.json"); let json = include_str!("READ_ME.json");
RichTextDelta::from_json(json).unwrap() TextDelta::from_json(json).unwrap()
} }
#[cfg(test)] #[cfg(test)]

View File

@ -9,30 +9,30 @@ use crate::{
use bytes::Bytes; use bytes::Bytes;
use lib_ot::{ use lib_ot::{
core::*, core::*,
rich_text::{RichTextDelta, TextAttribute}, text_delta::{TextAttribute, TextDelta},
}; };
use tokio::sync::mpsc; use tokio::sync::mpsc;
pub trait InitialDocumentText { pub trait InitialDocumentText {
fn initial_delta() -> RichTextDelta; fn initial_delta() -> TextDelta;
} }
pub struct PlainDoc(); pub struct PlainDoc();
impl InitialDocumentText for PlainDoc { impl InitialDocumentText for PlainDoc {
fn initial_delta() -> RichTextDelta { fn initial_delta() -> TextDelta {
RichTextDelta::new() TextDelta::new()
} }
} }
pub struct NewlineDoc(); pub struct NewlineDoc();
impl InitialDocumentText for NewlineDoc { impl InitialDocumentText for NewlineDoc {
fn initial_delta() -> RichTextDelta { fn initial_delta() -> TextDelta {
initial_quill_delta() initial_quill_delta()
} }
} }
pub struct ClientDocument { pub struct ClientDocument {
delta: RichTextDelta, delta: TextDelta,
history: History, history: History,
view: ViewExtensions, view: ViewExtensions,
last_edit_time: usize, last_edit_time: usize,
@ -44,7 +44,7 @@ impl ClientDocument {
Self::from_delta(C::initial_delta()) Self::from_delta(C::initial_delta())
} }
pub fn from_delta(delta: RichTextDelta) -> Self { pub fn from_delta(delta: TextDelta) -> Self {
ClientDocument { ClientDocument {
delta, delta,
history: History::new(), history: History::new(),
@ -55,7 +55,7 @@ impl ClientDocument {
} }
pub fn from_json(json: &str) -> Result<Self, CollaborateError> { pub fn from_json(json: &str) -> Result<Self, CollaborateError> {
let delta = RichTextDelta::from_json(json)?; let delta = TextDelta::from_json(json)?;
Ok(Self::from_delta(delta)) Ok(Self::from_delta(delta))
} }
@ -71,7 +71,7 @@ impl ClientDocument {
self.delta.apply("").unwrap() self.delta.apply("").unwrap()
} }
pub fn delta(&self) -> &RichTextDelta { pub fn delta(&self) -> &TextDelta {
&self.delta &self.delta
} }
@ -84,7 +84,7 @@ impl ClientDocument {
self.notify = Some(notify); self.notify = Some(notify);
} }
pub fn set_delta(&mut self, data: RichTextDelta) { pub fn set_delta(&mut self, data: TextDelta) {
tracing::trace!("document: {}", data.json_str()); tracing::trace!("document: {}", data.json_str());
self.delta = data; self.delta = data;
@ -96,7 +96,7 @@ impl ClientDocument {
} }
} }
pub fn compose_delta(&mut self, delta: RichTextDelta) -> Result<(), CollaborateError> { pub fn compose_delta(&mut self, delta: TextDelta) -> Result<(), CollaborateError> {
tracing::trace!("{} compose {}", &self.delta.json_str(), delta.json_str()); tracing::trace!("{} compose {}", &self.delta.json_str(), delta.json_str());
let composed_delta = self.delta.compose(&delta)?; let composed_delta = self.delta.compose(&delta)?;
let mut undo_delta = delta.invert(&self.delta); let mut undo_delta = delta.invert(&self.delta);
@ -122,7 +122,7 @@ impl ClientDocument {
Ok(()) Ok(())
} }
pub fn insert<T: ToString>(&mut self, index: usize, data: T) -> Result<RichTextDelta, CollaborateError> { pub fn insert<T: ToString>(&mut self, index: usize, data: T) -> Result<TextDelta, CollaborateError> {
let text = data.to_string(); let text = data.to_string();
let interval = Interval::new(index, index); let interval = Interval::new(index, index);
let _ = validate_interval(&self.delta, &interval)?; let _ = validate_interval(&self.delta, &interval)?;
@ -131,7 +131,7 @@ impl ClientDocument {
Ok(delta) Ok(delta)
} }
pub fn delete(&mut self, interval: Interval) -> Result<RichTextDelta, CollaborateError> { pub fn delete(&mut self, interval: Interval) -> Result<TextDelta, CollaborateError> {
let _ = validate_interval(&self.delta, &interval)?; let _ = validate_interval(&self.delta, &interval)?;
debug_assert!(!interval.is_empty()); debug_assert!(!interval.is_empty());
let delete = self.view.delete(&self.delta, interval)?; let delete = self.view.delete(&self.delta, interval)?;
@ -141,7 +141,7 @@ impl ClientDocument {
Ok(delete) Ok(delete)
} }
pub fn format(&mut self, interval: Interval, attribute: TextAttribute) -> Result<RichTextDelta, CollaborateError> { pub fn format(&mut self, interval: Interval, attribute: TextAttribute) -> Result<TextDelta, CollaborateError> {
let _ = validate_interval(&self.delta, &interval)?; let _ = validate_interval(&self.delta, &interval)?;
tracing::trace!("format {} with {}", interval, attribute); tracing::trace!("format {} with {}", interval, attribute);
let format_delta = self.view.format(&self.delta, attribute, interval).unwrap(); let format_delta = self.view.format(&self.delta, attribute, interval).unwrap();
@ -149,9 +149,9 @@ impl ClientDocument {
Ok(format_delta) Ok(format_delta)
} }
pub fn replace<T: ToString>(&mut self, interval: Interval, data: T) -> Result<RichTextDelta, CollaborateError> { pub fn replace<T: ToString>(&mut self, interval: Interval, data: T) -> Result<TextDelta, CollaborateError> {
let _ = validate_interval(&self.delta, &interval)?; let _ = validate_interval(&self.delta, &interval)?;
let mut delta = RichTextDelta::default(); let mut delta = TextDelta::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)?;
@ -205,7 +205,7 @@ impl ClientDocument {
} }
impl ClientDocument { impl ClientDocument {
fn invert(&self, delta: &RichTextDelta) -> Result<(RichTextDelta, RichTextDelta), CollaborateError> { fn invert(&self, delta: &TextDelta) -> Result<(TextDelta, TextDelta), CollaborateError> {
// c = a.compose(b) // c = a.compose(b)
// d = b.invert(a) // d = b.invert(a)
// a = c.compose(d) // a = c.compose(d)
@ -215,7 +215,7 @@ impl ClientDocument {
} }
} }
fn validate_interval(delta: &RichTextDelta, interval: &Interval) -> Result<(), CollaborateError> { fn validate_interval(delta: &TextDelta, interval: &Interval) -> Result<(), CollaborateError> {
if delta.utf16_target_len < interval.end { if delta.utf16_target_len < interval.end {
log::error!("{:?} out of bounds. should 0..{}", interval, delta.utf16_target_len); log::error!("{:?} out of bounds. should 0..{}", interval, delta.utf16_target_len);
return Err(CollaborateError::out_of_bound()); return Err(CollaborateError::out_of_bound());

View File

@ -1,7 +1,7 @@
use crate::client_document::DeleteExt; use crate::client_document::DeleteExt;
use lib_ot::{ use lib_ot::{
core::{DeltaBuilder, Interval}, core::{Interval, OperationBuilder},
rich_text::RichTextDelta, text_delta::TextDelta,
}; };
pub struct DefaultDelete {} pub struct DefaultDelete {}
@ -10,9 +10,9 @@ impl DeleteExt for DefaultDelete {
"DefaultDelete" "DefaultDelete"
} }
fn apply(&self, _delta: &RichTextDelta, interval: Interval) -> Option<RichTextDelta> { fn apply(&self, _delta: &TextDelta, interval: Interval) -> Option<TextDelta> {
Some( Some(
DeltaBuilder::new() OperationBuilder::new()
.retain(interval.start) .retain(interval.start)
.delete(interval.size()) .delete(interval.size())
.build(), .build(),

View File

@ -1,7 +1,7 @@
use crate::{client_document::DeleteExt, util::is_newline}; use crate::{client_document::DeleteExt, util::is_newline};
use lib_ot::{ use lib_ot::{
core::{Attributes, DeltaBuilder, DeltaIterator, Interval, Utf16CodeUnitMetric, NEW_LINE}, core::{Attributes, Interval, OperationBuilder, OperationIterator, Utf16CodeUnitMetric, NEW_LINE},
rich_text::{plain_attributes, RichTextDelta}, text_delta::{plain_attributes, TextDelta},
}; };
pub struct PreserveLineFormatOnMerge {} pub struct PreserveLineFormatOnMerge {}
@ -10,13 +10,13 @@ impl DeleteExt for PreserveLineFormatOnMerge {
"PreserveLineFormatOnMerge" "PreserveLineFormatOnMerge"
} }
fn apply(&self, delta: &RichTextDelta, interval: Interval) -> Option<RichTextDelta> { fn apply(&self, delta: &TextDelta, interval: Interval) -> Option<TextDelta> {
if interval.is_empty() { if interval.is_empty() {
return None; return None;
} }
// seek to the interval start pos. e.g. You backspace enter pos // seek to the interval start pos. e.g. You backspace enter pos
let mut iter = DeltaIterator::from_offset(delta, interval.start); let mut iter = OperationIterator::from_offset(delta, interval.start);
// op will be the "\n" // op will be the "\n"
let newline_op = iter.next_op_with_len(1)?; let newline_op = iter.next_op_with_len(1)?;
@ -25,7 +25,7 @@ impl DeleteExt for PreserveLineFormatOnMerge {
} }
iter.seek::<Utf16CodeUnitMetric>(interval.size() - 1); iter.seek::<Utf16CodeUnitMetric>(interval.size() - 1);
let mut new_delta = DeltaBuilder::new() let mut new_delta = OperationBuilder::new()
.retain(interval.start) .retain(interval.start)
.delete(interval.size()) .delete(interval.size())
.build(); .build();

View File

@ -1,6 +1,6 @@
use lib_ot::{ use lib_ot::{
core::{DeltaBuilder, DeltaIterator, Interval}, core::{Interval, OperationBuilder, OperationIterator},
rich_text::{plain_attributes, AttributeScope, RichTextDelta, TextAttribute}, text_delta::{plain_attributes, AttributeScope, TextAttribute, TextDelta},
}; };
use crate::{ use crate::{
@ -14,13 +14,13 @@ impl FormatExt for ResolveBlockFormat {
"ResolveBlockFormat" "ResolveBlockFormat"
} }
fn apply(&self, delta: &RichTextDelta, interval: Interval, attribute: &TextAttribute) -> Option<RichTextDelta> { fn apply(&self, delta: &TextDelta, interval: Interval, attribute: &TextAttribute) -> Option<TextDelta> {
if attribute.scope != AttributeScope::Block { if attribute.scope != AttributeScope::Block {
return None; return None;
} }
let mut new_delta = DeltaBuilder::new().retain(interval.start).build(); let mut new_delta = OperationBuilder::new().retain(interval.start).build();
let mut iter = DeltaIterator::from_offset(delta, interval.start); let mut iter = OperationIterator::from_offset(delta, interval.start);
let mut start = 0; let mut start = 0;
let end = interval.size(); let end = interval.size();
while start < end && iter.has_next() { while start < end && iter.has_next() {

View File

@ -1,6 +1,6 @@
use lib_ot::{ use lib_ot::{
core::{DeltaBuilder, DeltaIterator, Interval}, core::{Interval, OperationBuilder, OperationIterator},
rich_text::{AttributeScope, RichTextDelta, TextAttribute}, text_delta::{AttributeScope, TextAttribute, TextDelta},
}; };
use crate::{ use crate::{
@ -14,12 +14,12 @@ impl FormatExt for ResolveInlineFormat {
"ResolveInlineFormat" "ResolveInlineFormat"
} }
fn apply(&self, delta: &RichTextDelta, interval: Interval, attribute: &TextAttribute) -> Option<RichTextDelta> { fn apply(&self, delta: &TextDelta, interval: Interval, attribute: &TextAttribute) -> Option<TextDelta> {
if attribute.scope != AttributeScope::Inline { if attribute.scope != AttributeScope::Inline {
return None; return None;
} }
let mut new_delta = DeltaBuilder::new().retain(interval.start).build(); let mut new_delta = OperationBuilder::new().retain(interval.start).build();
let mut iter = DeltaIterator::from_offset(delta, interval.start); let mut iter = OperationIterator::from_offset(delta, interval.start);
let mut start = 0; let mut start = 0;
let end = interval.size(); let end = interval.size();

View File

@ -1,8 +1,8 @@
use crate::util::find_newline; use crate::util::find_newline;
use lib_ot::rich_text::{plain_attributes, AttributeScope, RichTextDelta, RichTextOperation, TextAttribute}; use lib_ot::text_delta::{plain_attributes, AttributeScope, RichTextOperation, TextAttribute, TextDelta};
pub(crate) fn line_break(op: &RichTextOperation, attribute: &TextAttribute, scope: AttributeScope) -> RichTextDelta { pub(crate) fn line_break(op: &RichTextOperation, attribute: &TextAttribute, scope: AttributeScope) -> TextDelta {
let mut new_delta = RichTextDelta::new(); let mut new_delta = TextDelta::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();

View File

@ -1,6 +1,6 @@
use crate::{client_document::InsertExt, util::is_newline}; use crate::{client_document::InsertExt, util::is_newline};
use lib_ot::core::{is_empty_line_at_index, DeltaBuilder, DeltaIterator}; use lib_ot::core::{is_empty_line_at_index, OperationBuilder, OperationIterator};
use lib_ot::rich_text::{attributes_except_header, RichTextDelta, TextAttributeKey}; use lib_ot::text_delta::{attributes_except_header, TextAttributeKey, TextDelta};
pub struct AutoExitBlock {} pub struct AutoExitBlock {}
@ -9,7 +9,7 @@ impl InsertExt for AutoExitBlock {
"AutoExitBlock" "AutoExitBlock"
} }
fn apply(&self, delta: &RichTextDelta, replace_len: usize, text: &str, index: usize) -> Option<RichTextDelta> { fn apply(&self, delta: &TextDelta, replace_len: usize, text: &str, index: usize) -> Option<TextDelta> {
// 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;
@ -19,7 +19,7 @@ impl InsertExt for AutoExitBlock {
return None; return None;
} }
let mut iter = DeltaIterator::from_offset(delta, index); let mut iter = OperationIterator::from_offset(delta, index);
let next = iter.next_op()?; let next = iter.next_op()?;
let mut attributes = next.get_attributes(); let mut attributes = next.get_attributes();
@ -45,7 +45,7 @@ impl InsertExt for AutoExitBlock {
attributes.mark_all_as_removed_except(Some(TextAttributeKey::Header)); attributes.mark_all_as_removed_except(Some(TextAttributeKey::Header));
Some( Some(
DeltaBuilder::new() OperationBuilder::new()
.retain(index + replace_len) .retain(index + replace_len)
.retain_with_attributes(1, attributes) .retain_with_attributes(1, attributes)
.build(), .build(),

View File

@ -1,7 +1,7 @@
use crate::{client_document::InsertExt, util::is_whitespace}; use crate::{client_document::InsertExt, util::is_whitespace};
use lib_ot::{ use lib_ot::{
core::{count_utf16_code_units, DeltaBuilder, DeltaIterator}, core::{count_utf16_code_units, OperationBuilder, OperationIterator},
rich_text::{plain_attributes, RichTextDelta, TextAttribute, TextAttributes}, text_delta::{plain_attributes, TextAttribute, TextAttributes, TextDelta},
}; };
use std::cmp::min; use std::cmp::min;
use url::Url; use url::Url;
@ -12,12 +12,12 @@ impl InsertExt for AutoFormatExt {
"AutoFormatExt" "AutoFormatExt"
} }
fn apply(&self, delta: &RichTextDelta, replace_len: usize, text: &str, index: usize) -> Option<RichTextDelta> { fn apply(&self, delta: &TextDelta, replace_len: usize, text: &str, index: usize) -> Option<TextDelta> {
// enter whitespace to trigger auto format // enter whitespace to trigger auto format
if !is_whitespace(text) { if !is_whitespace(text) {
return None; return None;
} }
let mut iter = DeltaIterator::new(delta); let mut iter = OperationIterator::new(delta);
if let Some(prev) = iter.next_op_with_len(index) { if let Some(prev) = iter.next_op_with_len(index) {
match AutoFormat::parse(prev.get_data()) { match AutoFormat::parse(prev.get_data()) {
None => {} None => {}
@ -41,7 +41,7 @@ impl InsertExt for AutoFormatExt {
}; };
return Some( return Some(
DeltaBuilder::new() OperationBuilder::new()
.retain(index + replace_len - min(index, format_len)) .retain(index + replace_len - min(index, format_len))
.retain_with_attributes(format_len, format_attributes) .retain_with_attributes(format_len, format_attributes)
.insert_with_attributes(text, next_attributes) .insert_with_attributes(text, next_attributes)

View File

@ -1,7 +1,7 @@
use crate::client_document::InsertExt; use crate::client_document::InsertExt;
use lib_ot::{ use lib_ot::{
core::{Attributes, DeltaBuilder, DeltaIterator, NEW_LINE}, core::{Attributes, OperationBuilder, OperationIterator, NEW_LINE},
rich_text::{RichTextDelta, TextAttributeKey, TextAttributes}, text_delta::{TextAttributeKey, TextAttributes, TextDelta},
}; };
pub struct DefaultInsertAttribute {} pub struct DefaultInsertAttribute {}
@ -10,8 +10,8 @@ impl InsertExt for DefaultInsertAttribute {
"DefaultInsertAttribute" "DefaultInsertAttribute"
} }
fn apply(&self, delta: &RichTextDelta, replace_len: usize, text: &str, index: usize) -> Option<RichTextDelta> { fn apply(&self, delta: &TextDelta, replace_len: usize, text: &str, index: usize) -> Option<TextDelta> {
let iter = DeltaIterator::new(delta); let iter = OperationIterator::new(delta);
let mut attributes = TextAttributes::new(); let mut attributes = TextAttributes::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:
@ -31,7 +31,7 @@ impl InsertExt for DefaultInsertAttribute {
} }
Some( Some(
DeltaBuilder::new() OperationBuilder::new()
.retain(index + replace_len) .retain(index + replace_len)
.insert_with_attributes(text, attributes) .insert_with_attributes(text, attributes)
.build(), .build(),

View File

@ -2,7 +2,7 @@ use crate::client_document::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::rich_text::RichTextDelta; use lib_ot::text_delta::TextDelta;
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::*;
@ -20,7 +20,7 @@ impl InsertExt for InsertEmbedsExt {
"InsertEmbedsExt" "InsertEmbedsExt"
} }
fn apply(&self, _delta: &RichTextDelta, _replace_len: usize, _text: &str, _index: usize) -> Option<RichTextDelta> { fn apply(&self, _delta: &TextDelta, _replace_len: usize, _text: &str, _index: usize) -> Option<TextDelta> {
None None
} }
} }
@ -31,7 +31,7 @@ impl InsertExt for ForceNewlineForInsertsAroundEmbedExt {
"ForceNewlineForInsertsAroundEmbedExt" "ForceNewlineForInsertsAroundEmbedExt"
} }
fn apply(&self, _delta: &RichTextDelta, _replace_len: usize, _text: &str, _index: usize) -> Option<RichTextDelta> { fn apply(&self, _delta: &TextDelta, _replace_len: usize, _text: &str, _index: usize) -> Option<TextDelta> {
None None
} }
} }

View File

@ -1,8 +1,8 @@
use crate::{client_document::InsertExt, util::is_newline}; use crate::{client_document::InsertExt, util::is_newline};
use lib_ot::{ use lib_ot::{
core::{DeltaBuilder, DeltaIterator, NEW_LINE}, core::{OperationBuilder, OperationIterator, NEW_LINE},
rich_text::{ text_delta::{
attributes_except_header, plain_attributes, RichTextDelta, TextAttribute, TextAttributeKey, TextAttributes, attributes_except_header, plain_attributes, TextAttribute, TextAttributeKey, TextAttributes, TextDelta,
}, },
}; };
@ -12,12 +12,12 @@ impl InsertExt for PreserveBlockFormatOnInsert {
"PreserveBlockFormatOnInsert" "PreserveBlockFormatOnInsert"
} }
fn apply(&self, delta: &RichTextDelta, replace_len: usize, text: &str, index: usize) -> Option<RichTextDelta> { fn apply(&self, delta: &TextDelta, replace_len: usize, text: &str, index: usize) -> Option<TextDelta> {
if !is_newline(text) { if !is_newline(text) {
return None; return None;
} }
let mut iter = DeltaIterator::from_offset(delta, index); let mut iter = OperationIterator::from_offset(delta, index);
match iter.next_op_with_newline() { match iter.next_op_with_newline() {
None => {} None => {}
Some((newline_op, offset)) => { Some((newline_op, offset)) => {
@ -33,7 +33,7 @@ impl InsertExt for PreserveBlockFormatOnInsert {
} }
let lines: Vec<_> = text.split(NEW_LINE).collect(); let lines: Vec<_> = text.split(NEW_LINE).collect();
let mut new_delta = DeltaBuilder::new().retain(index + replace_len).build(); let mut new_delta = OperationBuilder::new().retain(index + replace_len).build();
lines.iter().enumerate().for_each(|(i, line)| { lines.iter().enumerate().for_each(|(i, line)| {
if !line.is_empty() { if !line.is_empty() {
new_delta.insert(line, plain_attributes()); new_delta.insert(line, plain_attributes());

View File

@ -3,8 +3,8 @@ use crate::{
util::{contain_newline, is_newline}, util::{contain_newline, is_newline},
}; };
use lib_ot::{ use lib_ot::{
core::{DeltaBuilder, DeltaIterator, OpNewline, NEW_LINE}, core::{OpNewline, OperationBuilder, OperationIterator, NEW_LINE},
rich_text::{plain_attributes, RichTextDelta, TextAttributeKey}, text_delta::{plain_attributes, TextAttributeKey, TextDelta},
}; };
pub struct PreserveInlineFormat {} pub struct PreserveInlineFormat {}
@ -13,12 +13,12 @@ impl InsertExt for PreserveInlineFormat {
"PreserveInlineFormat" "PreserveInlineFormat"
} }
fn apply(&self, delta: &RichTextDelta, replace_len: usize, text: &str, index: usize) -> Option<RichTextDelta> { fn apply(&self, delta: &TextDelta, replace_len: usize, text: &str, index: usize) -> Option<TextDelta> {
if contain_newline(text) { if contain_newline(text) {
return None; return None;
} }
let mut iter = DeltaIterator::new(delta); let mut iter = OperationIterator::new(delta);
let prev = iter.next_op_with_len(index)?; let prev = iter.next_op_with_len(index)?;
if OpNewline::parse(&prev).is_contain() { if OpNewline::parse(&prev).is_contain() {
return None; return None;
@ -27,7 +27,7 @@ impl InsertExt for PreserveInlineFormat {
let mut attributes = prev.get_attributes(); let mut attributes = prev.get_attributes();
if attributes.is_empty() || !attributes.contains_key(&TextAttributeKey::Link) { if attributes.is_empty() || !attributes.contains_key(&TextAttributeKey::Link) {
return Some( return Some(
DeltaBuilder::new() OperationBuilder::new()
.retain(index + replace_len) .retain(index + replace_len)
.insert_with_attributes(text, attributes) .insert_with_attributes(text, attributes)
.build(), .build(),
@ -44,7 +44,7 @@ impl InsertExt for PreserveInlineFormat {
} }
} }
let new_delta = DeltaBuilder::new() let new_delta = OperationBuilder::new()
.retain(index + replace_len) .retain(index + replace_len)
.insert_with_attributes(text, attributes) .insert_with_attributes(text, attributes)
.build(); .build();
@ -59,12 +59,12 @@ impl InsertExt for PreserveLineFormatOnSplit {
"PreserveLineFormatOnSplit" "PreserveLineFormatOnSplit"
} }
fn apply(&self, delta: &RichTextDelta, replace_len: usize, text: &str, index: usize) -> Option<RichTextDelta> { fn apply(&self, delta: &TextDelta, replace_len: usize, text: &str, index: usize) -> Option<TextDelta> {
if !is_newline(text) { if !is_newline(text) {
return None; return None;
} }
let mut iter = DeltaIterator::new(delta); let mut iter = OperationIterator::new(delta);
let prev = iter.next_op_with_len(index)?; let prev = iter.next_op_with_len(index)?;
if OpNewline::parse(&prev).is_end() { if OpNewline::parse(&prev).is_end() {
return None; return None;
@ -76,7 +76,7 @@ impl InsertExt for PreserveLineFormatOnSplit {
return None; return None;
} }
let mut new_delta = RichTextDelta::new(); let mut new_delta = TextDelta::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() {

View File

@ -1,7 +1,7 @@
use crate::{client_document::InsertExt, util::is_newline}; use crate::{client_document::InsertExt, util::is_newline};
use lib_ot::{ use lib_ot::{
core::{DeltaBuilder, DeltaIterator, Utf16CodeUnitMetric, NEW_LINE}, core::{OperationBuilder, OperationIterator, Utf16CodeUnitMetric, NEW_LINE},
rich_text::{RichTextDelta, TextAttributeKey, TextAttributes}, text_delta::{TextAttributeKey, TextAttributes, TextDelta},
}; };
pub struct ResetLineFormatOnNewLine {} pub struct ResetLineFormatOnNewLine {}
@ -10,12 +10,12 @@ impl InsertExt for ResetLineFormatOnNewLine {
"ResetLineFormatOnNewLine" "ResetLineFormatOnNewLine"
} }
fn apply(&self, delta: &RichTextDelta, replace_len: usize, text: &str, index: usize) -> Option<RichTextDelta> { fn apply(&self, delta: &TextDelta, replace_len: usize, text: &str, index: usize) -> Option<TextDelta> {
if !is_newline(text) { if !is_newline(text) {
return None; return None;
} }
let mut iter = DeltaIterator::new(delta); let mut iter = OperationIterator::new(delta);
iter.seek::<Utf16CodeUnitMetric>(index); iter.seek::<Utf16CodeUnitMetric>(index);
let next_op = iter.next_op()?; let next_op = iter.next_op()?;
if !next_op.get_data().starts_with(NEW_LINE) { if !next_op.get_data().starts_with(NEW_LINE) {
@ -29,7 +29,7 @@ impl InsertExt for ResetLineFormatOnNewLine {
let len = index + replace_len; let len = index + replace_len;
Some( Some(
DeltaBuilder::new() OperationBuilder::new()
.retain(len) .retain(len)
.insert_with_attributes(NEW_LINE, next_op.get_attributes()) .insert_with_attributes(NEW_LINE, next_op.get_attributes())
.retain_with_attributes(1, reset_attribute) .retain_with_attributes(1, reset_attribute)

View File

@ -3,7 +3,7 @@ pub use format::*;
pub use insert::*; pub use insert::*;
use lib_ot::{ use lib_ot::{
core::Interval, core::Interval,
rich_text::{RichTextDelta, TextAttribute}, text_delta::{TextAttribute, TextDelta},
}; };
mod delete; mod delete;
@ -17,15 +17,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: &RichTextDelta, replace_len: usize, text: &str, index: usize) -> Option<RichTextDelta>; fn apply(&self, delta: &TextDelta, replace_len: usize, text: &str, index: usize) -> Option<TextDelta>;
} }
pub trait FormatExt { pub trait FormatExt {
fn ext_name(&self) -> &str; fn ext_name(&self) -> &str;
fn apply(&self, delta: &RichTextDelta, interval: Interval, attribute: &TextAttribute) -> Option<RichTextDelta>; fn apply(&self, delta: &TextDelta, interval: Interval, attribute: &TextAttribute) -> Option<TextDelta>;
} }
pub trait DeleteExt { pub trait DeleteExt {
fn ext_name(&self) -> &str; fn ext_name(&self) -> &str;
fn apply(&self, delta: &RichTextDelta, interval: Interval) -> Option<RichTextDelta>; fn apply(&self, delta: &TextDelta, interval: Interval) -> Option<TextDelta>;
} }

View File

@ -1,18 +1,18 @@
use lib_ot::rich_text::RichTextDelta; use lib_ot::text_delta::TextDelta;
const MAX_UNDOES: usize = 20; const MAX_UNDOES: usize = 20;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct UndoResult { pub struct UndoResult {
pub delta: RichTextDelta, pub delta: TextDelta,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct History { pub struct History {
#[allow(dead_code)] #[allow(dead_code)]
cur_undo: usize, cur_undo: usize,
undoes: Vec<RichTextDelta>, undoes: Vec<TextDelta>,
redoes: Vec<RichTextDelta>, redoes: Vec<TextDelta>,
capacity: usize, capacity: usize,
} }
@ -40,15 +40,15 @@ impl History {
!self.redoes.is_empty() !self.redoes.is_empty()
} }
pub fn add_undo(&mut self, delta: RichTextDelta) { pub fn add_undo(&mut self, delta: TextDelta) {
self.undoes.push(delta); self.undoes.push(delta);
} }
pub fn add_redo(&mut self, delta: RichTextDelta) { pub fn add_redo(&mut self, delta: TextDelta) {
self.redoes.push(delta); self.redoes.push(delta);
} }
pub fn record(&mut self, delta: RichTextDelta) { pub fn record(&mut self, delta: TextDelta) {
if delta.ops.is_empty() { if delta.ops.is_empty() {
return; return;
} }
@ -61,7 +61,7 @@ impl History {
} }
} }
pub fn undo(&mut self) -> Option<RichTextDelta> { pub fn undo(&mut self) -> Option<TextDelta> {
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<RichTextDelta> { pub fn redo(&mut self) -> Option<TextDelta> {
if !self.can_redo() { if !self.can_redo() {
return None; return None;
} }

View File

@ -2,7 +2,7 @@ use crate::client_document::*;
use lib_ot::{ use lib_ot::{
core::{trim, Interval}, core::{trim, Interval},
errors::{ErrorBuilder, OTError, OTErrorCode}, errors::{ErrorBuilder, OTError, OTErrorCode},
rich_text::{RichTextDelta, TextAttribute}, text_delta::{TextAttribute, TextDelta},
}; };
pub const RECORD_THRESHOLD: usize = 400; // in milliseconds pub const RECORD_THRESHOLD: usize = 400; // in milliseconds
@ -22,12 +22,7 @@ impl ViewExtensions {
} }
} }
pub(crate) fn insert( pub(crate) fn insert(&self, delta: &TextDelta, text: &str, interval: Interval) -> Result<TextDelta, OTError> {
&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) {
@ -44,7 +39,7 @@ impl ViewExtensions {
} }
} }
pub(crate) fn delete(&self, delta: &RichTextDelta, interval: Interval) -> Result<RichTextDelta, OTError> { pub(crate) fn delete(&self, delta: &TextDelta, interval: Interval) -> Result<TextDelta, 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) {
@ -63,10 +58,10 @@ impl ViewExtensions {
pub(crate) fn format( pub(crate) fn format(
&self, &self,
delta: &RichTextDelta, delta: &TextDelta,
attribute: TextAttribute, attribute: TextAttribute,
interval: Interval, interval: Interval,
) -> Result<RichTextDelta, OTError> { ) -> Result<TextDelta, 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) {

View File

@ -32,7 +32,7 @@ impl FolderPad {
pub fn from_folder_rev(folder_rev: FolderRevision) -> CollaborateResult<Self> { pub fn from_folder_rev(folder_rev: FolderRevision) -> CollaborateResult<Self> {
let json = serde_json::to_string(&folder_rev) let json = serde_json::to_string(&folder_rev)
.map_err(|e| CollaborateError::internal().context(format!("Serialize to folder json str failed: {}", e)))?; .map_err(|e| CollaborateError::internal().context(format!("Serialize to folder json str failed: {}", e)))?;
let delta = TextDeltaBuilder::new().insert(&json).build(); let delta = DeltaBuilder::new().insert(&json).build();
Ok(Self { folder_rev, delta }) Ok(Self { folder_rev, delta })
} }
@ -340,7 +340,7 @@ impl FolderPad {
Some(_) => { Some(_) => {
let old = cloned_self.to_json()?; let old = cloned_self.to_json()?;
let new = self.to_json()?; let new = self.to_json()?;
match cal_diff::<PhantomAttributes>(old, new) { match cal_diff::<EmptyAttributes>(old, new) {
None => Ok(None), None => Ok(None),
Some(delta) => { Some(delta) => {
self.delta = self.delta.compose(&delta)?; self.delta = self.delta.compose(&delta)?;
@ -375,7 +375,7 @@ impl FolderPad {
Some(_) => { Some(_) => {
let old = cloned_self.to_json()?; let old = cloned_self.to_json()?;
let new = self.to_json()?; let new = self.to_json()?;
match cal_diff::<PhantomAttributes>(old, new) { match cal_diff::<EmptyAttributes>(old, new) {
None => Ok(None), None => Ok(None),
Some(delta) => { Some(delta) => {
self.delta = self.delta.compose(&delta)?; self.delta = self.delta.compose(&delta)?;
@ -426,14 +426,12 @@ impl FolderPad {
} }
pub fn default_folder_delta() -> FolderDelta { pub fn default_folder_delta() -> FolderDelta {
TextDeltaBuilder::new() DeltaBuilder::new().insert(r#"{"workspaces":[],"trash":[]}"#).build()
.insert(r#"{"workspaces":[],"trash":[]}"#)
.build()
} }
pub fn initial_folder_delta(folder_pad: &FolderPad) -> CollaborateResult<FolderDelta> { pub fn initial_folder_delta(folder_pad: &FolderPad) -> CollaborateResult<FolderDelta> {
let json = folder_pad.to_json()?; let json = folder_pad.to_json()?;
let delta = TextDeltaBuilder::new().insert(&json).build(); let delta = DeltaBuilder::new().insert(&json).build();
Ok(delta) Ok(delta)
} }
@ -461,7 +459,7 @@ mod tests {
use flowy_folder_data_model::revision::{ use flowy_folder_data_model::revision::{
AppRevision, FolderRevision, TrashRevision, ViewRevision, WorkspaceRevision, AppRevision, FolderRevision, TrashRevision, ViewRevision, WorkspaceRevision,
}; };
use lib_ot::core::{OperationTransform, TextDelta, TextDeltaBuilder}; use lib_ot::core::{Delta, DeltaBuilder, OperationTransform};
#[test] #[test]
fn folder_add_workspace() { fn folder_add_workspace() {
@ -776,7 +774,7 @@ mod tests {
fn test_folder() -> (FolderPad, FolderDelta, WorkspaceRevision) { fn test_folder() -> (FolderPad, FolderDelta, WorkspaceRevision) {
let folder_rev = FolderRevision::default(); let folder_rev = FolderRevision::default();
let folder_json = serde_json::to_string(&folder_rev).unwrap(); let folder_json = serde_json::to_string(&folder_rev).unwrap();
let mut delta = TextDeltaBuilder::new().insert(&folder_json).build(); let mut delta = DeltaBuilder::new().insert(&folder_json).build();
let mut workspace_rev = WorkspaceRevision::default(); let mut workspace_rev = WorkspaceRevision::default();
workspace_rev.name = "😁 my first workspace".to_owned(); workspace_rev.name = "😁 my first workspace".to_owned();
@ -820,7 +818,7 @@ mod tests {
fn test_trash() -> (FolderPad, FolderDelta, TrashRevision) { fn test_trash() -> (FolderPad, FolderDelta, TrashRevision) {
let folder_rev = FolderRevision::default(); let folder_rev = FolderRevision::default();
let folder_json = serde_json::to_string(&folder_rev).unwrap(); let folder_json = serde_json::to_string(&folder_rev).unwrap();
let mut delta = TextDeltaBuilder::new().insert(&folder_json).build(); let mut delta = DeltaBuilder::new().insert(&folder_json).build();
let mut trash_rev = TrashRevision::default(); let mut trash_rev = TrashRevision::default();
trash_rev.name = "🚽 my first trash".to_owned(); trash_rev.name = "🚽 my first trash".to_owned();
@ -839,7 +837,7 @@ mod tests {
(folder, delta, trash_rev) (folder, delta, trash_rev)
} }
fn make_folder_from_delta(mut initial_delta: FolderDelta, deltas: Vec<TextDelta>) -> FolderPad { fn make_folder_from_delta(mut initial_delta: FolderDelta, deltas: Vec<Delta>) -> FolderPad {
for delta in deltas { for delta in deltas {
initial_delta = initial_delta.compose(&delta).unwrap(); initial_delta = initial_delta.compose(&delta).unwrap();
} }

View File

@ -4,7 +4,7 @@ use crate::util::{cal_diff, make_text_delta_from_revisions};
use flowy_grid_data_model::revision::{ use flowy_grid_data_model::revision::{
gen_block_id, gen_row_id, CellRevision, GridBlockRevision, RowChangeset, RowRevision, gen_block_id, gen_row_id, CellRevision, GridBlockRevision, RowChangeset, RowRevision,
}; };
use lib_ot::core::{OperationTransform, PhantomAttributes, TextDelta, TextDeltaBuilder}; use lib_ot::core::{Delta, DeltaBuilder, EmptyAttributes, OperationTransform};
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
@ -12,7 +12,7 @@ use std::sync::Arc;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct GridBlockRevisionPad { pub struct GridBlockRevisionPad {
block: GridBlockRevision, block: GridBlockRevision,
delta: TextDelta, delta: Delta,
} }
impl std::ops::Deref for GridBlockRevisionPad { impl std::ops::Deref for GridBlockRevisionPad {
@ -42,7 +42,7 @@ impl GridBlockRevisionPad {
} }
} }
pub fn from_delta(delta: TextDelta) -> CollaborateResult<Self> { pub fn from_delta(delta: Delta) -> CollaborateResult<Self> {
let s = delta.content()?; let s = delta.content()?;
let revision: GridBlockRevision = serde_json::from_str(&s).map_err(|e| { let revision: GridBlockRevision = serde_json::from_str(&s).map_err(|e| {
let msg = format!("Deserialize delta to GridBlockRevision failed: {}", e); let msg = format!("Deserialize delta to GridBlockRevision failed: {}", e);
@ -53,7 +53,7 @@ impl GridBlockRevisionPad {
} }
pub fn from_revisions(_grid_id: &str, revisions: Vec<Revision>) -> CollaborateResult<Self> { pub fn from_revisions(_grid_id: &str, revisions: Vec<Revision>) -> CollaborateResult<Self> {
let block_delta: TextDelta = make_text_delta_from_revisions(revisions)?; let block_delta: Delta = make_text_delta_from_revisions(revisions)?;
Self::from_delta(block_delta) Self::from_delta(block_delta)
} }
@ -200,7 +200,7 @@ impl GridBlockRevisionPad {
Some(_) => { Some(_) => {
let old = cloned_self.revision_json()?; let old = cloned_self.revision_json()?;
let new = self.revision_json()?; let new = self.revision_json()?;
match cal_diff::<PhantomAttributes>(old, new) { match cal_diff::<EmptyAttributes>(old, new) {
None => Ok(None), None => Ok(None),
Some(delta) => { Some(delta) => {
tracing::trace!("[GridBlockRevision] Composing delta {}", delta.json_str()); tracing::trace!("[GridBlockRevision] Composing delta {}", delta.json_str());
@ -240,14 +240,14 @@ impl GridBlockRevisionPad {
} }
pub struct GridBlockRevisionChangeset { pub struct GridBlockRevisionChangeset {
pub delta: TextDelta, pub delta: Delta,
/// md5: the md5 of the grid after applying the change. /// md5: the md5 of the grid after applying the change.
pub md5: String, pub md5: String,
} }
pub fn make_grid_block_delta(block_rev: &GridBlockRevision) -> TextDelta { pub fn make_grid_block_delta(block_rev: &GridBlockRevision) -> Delta {
let json = serde_json::to_string(&block_rev).unwrap(); let json = serde_json::to_string(&block_rev).unwrap();
TextDeltaBuilder::new().insert(&json).build() DeltaBuilder::new().insert(&json).build()
} }
pub fn make_grid_block_revisions(user_id: &str, grid_block_meta_data: &GridBlockRevision) -> RepeatedRevision { pub fn make_grid_block_revisions(user_id: &str, grid_block_meta_data: &GridBlockRevision) -> RepeatedRevision {
@ -276,7 +276,7 @@ impl std::default::Default for GridBlockRevisionPad {
mod tests { mod tests {
use crate::client_grid::GridBlockRevisionPad; use crate::client_grid::GridBlockRevisionPad;
use flowy_grid_data_model::revision::{RowChangeset, RowRevision}; use flowy_grid_data_model::revision::{RowChangeset, RowRevision};
use lib_ot::core::TextDelta; use lib_ot::core::Delta;
use std::borrow::Cow; use std::borrow::Cow;
#[test] #[test]
@ -422,7 +422,7 @@ mod tests {
} }
fn test_pad() -> GridBlockRevisionPad { fn test_pad() -> GridBlockRevisionPad {
let delta = TextDelta::from_json(r#"[{"insert":"{\"block_id\":\"1\",\"rows\":[]}"}]"#).unwrap(); let delta = Delta::from_json(r#"[{"insert":"{\"block_id\":\"1\",\"rows\":[]}"}]"#).unwrap();
GridBlockRevisionPad::from_delta(delta).unwrap() GridBlockRevisionPad::from_delta(delta).unwrap()
} }
} }

View File

@ -7,12 +7,12 @@ use flowy_grid_data_model::revision::{
GridRevision, GridRevision,
}; };
use lib_infra::util::move_vec_element; use lib_infra::util::move_vec_element;
use lib_ot::core::{OperationTransform, PhantomAttributes, TextDelta, TextDeltaBuilder}; use lib_ot::core::{Delta, DeltaBuilder, EmptyAttributes, OperationTransform};
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
pub type GridRevisionDelta = TextDelta; pub type GridRevisionDelta = Delta;
pub type GridRevisionDeltaBuilder = TextDeltaBuilder; pub type GridRevisionDeltaBuilder = DeltaBuilder;
pub struct GridRevisionPad { pub struct GridRevisionPad {
grid_rev: Arc<GridRevision>, grid_rev: Arc<GridRevision>,
@ -314,7 +314,7 @@ impl GridRevisionPad {
Some(_) => { Some(_) => {
let old = make_grid_rev_json_str(&cloned_grid)?; let old = make_grid_rev_json_str(&cloned_grid)?;
let new = self.json_str()?; let new = self.json_str()?;
match cal_diff::<PhantomAttributes>(old, new) { match cal_diff::<EmptyAttributes>(old, new) {
None => Ok(None), None => Ok(None),
Some(delta) => { Some(delta) => {
self.delta = self.delta.compose(&delta)?; self.delta = self.delta.compose(&delta)?;
@ -380,7 +380,7 @@ pub struct GridRevisionChangeset {
pub fn make_grid_delta(grid_rev: &GridRevision) -> GridRevisionDelta { pub fn make_grid_delta(grid_rev: &GridRevision) -> GridRevisionDelta {
let json = serde_json::to_string(&grid_rev).unwrap(); let json = serde_json::to_string(&grid_rev).unwrap();
TextDeltaBuilder::new().insert(&json).build() DeltaBuilder::new().insert(&json).build()
} }
pub fn make_grid_revisions(user_id: &str, grid_rev: &GridRevision) -> RepeatedRevision { pub fn make_grid_revisions(user_id: &str, grid_rev: &GridRevision) -> RepeatedRevision {

View File

@ -5,13 +5,13 @@ use flowy_grid_data_model::revision::{
FieldRevision, FieldTypeRevision, FilterConfigurationRevision, FilterConfigurationsByFieldId, GridViewRevision, FieldRevision, FieldTypeRevision, FilterConfigurationRevision, FilterConfigurationsByFieldId, GridViewRevision,
GroupConfigurationRevision, GroupConfigurationsByFieldId, GroupConfigurationRevision, GroupConfigurationsByFieldId,
}; };
use lib_ot::core::{OperationTransform, PhantomAttributes, TextDelta, TextDeltaBuilder}; use lib_ot::core::{Delta, DeltaBuilder, EmptyAttributes, OperationTransform};
use std::sync::Arc; use std::sync::Arc;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct GridViewRevisionPad { pub struct GridViewRevisionPad {
view: Arc<GridViewRevision>, view: Arc<GridViewRevision>,
delta: TextDelta, delta: Delta,
} }
impl std::ops::Deref for GridViewRevisionPad { impl std::ops::Deref for GridViewRevisionPad {
@ -26,11 +26,11 @@ impl GridViewRevisionPad {
pub fn new(grid_id: String, view_id: String) -> Self { pub fn new(grid_id: String, view_id: String) -> Self {
let view = Arc::new(GridViewRevision::new(grid_id, view_id)); let view = Arc::new(GridViewRevision::new(grid_id, view_id));
let json = serde_json::to_string(&view).unwrap(); let json = serde_json::to_string(&view).unwrap();
let delta = TextDeltaBuilder::new().insert(&json).build(); let delta = DeltaBuilder::new().insert(&json).build();
Self { view, delta } Self { view, delta }
} }
pub fn from_delta(delta: TextDelta) -> CollaborateResult<Self> { pub fn from_delta(delta: Delta) -> CollaborateResult<Self> {
let s = delta.content()?; let s = delta.content()?;
let view: GridViewRevision = serde_json::from_str(&s).map_err(|e| { let view: GridViewRevision = serde_json::from_str(&s).map_err(|e| {
let msg = format!("Deserialize delta to GridViewRevision failed: {}", e); let msg = format!("Deserialize delta to GridViewRevision failed: {}", e);
@ -44,7 +44,7 @@ impl GridViewRevisionPad {
} }
pub fn from_revisions(_grid_id: &str, revisions: Vec<Revision>) -> CollaborateResult<Self> { pub fn from_revisions(_grid_id: &str, revisions: Vec<Revision>) -> CollaborateResult<Self> {
let delta: TextDelta = make_text_delta_from_revisions(revisions)?; let delta: Delta = make_text_delta_from_revisions(revisions)?;
Self::from_delta(delta) Self::from_delta(delta)
} }
@ -168,7 +168,7 @@ impl GridViewRevisionPad {
Some(_) => { Some(_) => {
let old = make_grid_view_rev_json_str(&cloned_view)?; let old = make_grid_view_rev_json_str(&cloned_view)?;
let new = self.json_str()?; let new = self.json_str()?;
match cal_diff::<PhantomAttributes>(old, new) { match cal_diff::<EmptyAttributes>(old, new) {
None => Ok(None), None => Ok(None),
Some(delta) => { Some(delta) => {
self.delta = self.delta.compose(&delta)?; self.delta = self.delta.compose(&delta)?;
@ -183,7 +183,7 @@ impl GridViewRevisionPad {
#[derive(Debug)] #[derive(Debug)]
pub struct GridViewRevisionChangeset { pub struct GridViewRevisionChangeset {
pub delta: TextDelta, pub delta: Delta,
pub md5: String, pub md5: String,
} }
@ -193,7 +193,7 @@ pub fn make_grid_view_rev_json_str(grid_revision: &GridViewRevision) -> Collabor
Ok(json) Ok(json)
} }
pub fn make_grid_view_delta(grid_view: &GridViewRevision) -> TextDelta { pub fn make_grid_view_delta(grid_view: &GridViewRevision) -> Delta {
let json = serde_json::to_string(grid_view).unwrap(); let json = serde_json::to_string(grid_view).unwrap();
TextDeltaBuilder::new().insert(&json).build() DeltaBuilder::new().insert(&json).build()
} }

View File

@ -1,7 +1,7 @@
use flowy_derive::ProtoBuf; use flowy_derive::ProtoBuf;
use lib_ot::core::TextDelta; use lib_ot::core::Delta;
pub type FolderDelta = TextDelta; pub type FolderDelta = Delta;
#[derive(ProtoBuf, Default, Debug, Clone, Eq, PartialEq)] #[derive(ProtoBuf, Default, Debug, Clone, Eq, PartialEq)]
pub struct FolderInfo { pub struct FolderInfo {

View File

@ -1,6 +1,6 @@
use bytes::Bytes; use bytes::Bytes;
use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
use lib_ot::rich_text::RichTextDelta; use lib_ot::text_delta::TextDelta;
use std::{convert::TryFrom, fmt::Formatter, ops::RangeInclusive}; use std::{convert::TryFrom, fmt::Formatter, ops::RangeInclusive};
#[derive(PartialEq, Eq, Clone, Default, ProtoBuf)] #[derive(PartialEq, Eq, Clone, Default, ProtoBuf)]
@ -87,7 +87,7 @@ impl std::fmt::Debug for Revision {
let _ = f.write_fmt(format_args!("object_id {}, ", self.object_id))?; let _ = f.write_fmt(format_args!("object_id {}, ", self.object_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 RichTextDelta::from_bytes(&self.delta_data) { match TextDelta::from_bytes(&self.delta_data) {
Ok(delta) => { Ok(delta) => {
let _ = f.write_fmt(format_args!("delta {:?}", delta.json_str()))?; let _ = f.write_fmt(format_args!("delta {:?}", delta.json_str()))?;
} }

View File

@ -3,7 +3,7 @@ use crate::{
errors::CollaborateError, errors::CollaborateError,
}; };
use flowy_derive::ProtoBuf; use flowy_derive::ProtoBuf;
use lib_ot::{errors::OTError, rich_text::RichTextDelta}; use lib_ot::{errors::OTError, text_delta::TextDelta};
#[derive(ProtoBuf, Default, Debug, Clone)] #[derive(ProtoBuf, Default, Debug, Clone)]
pub struct CreateTextBlockParams { pub struct CreateTextBlockParams {
@ -30,8 +30,8 @@ pub struct DocumentPB {
} }
impl DocumentPB { impl DocumentPB {
pub fn delta(&self) -> Result<RichTextDelta, OTError> { pub fn delta(&self) -> Result<TextDelta, OTError> {
let delta = RichTextDelta::from_bytes(&self.text)?; let delta = TextDelta::from_bytes(&self.text)?;
Ok(delta) Ok(delta)
} }
} }
@ -45,7 +45,7 @@ impl std::convert::TryFrom<Revision> for DocumentPB {
.context("Revision's rev_id should be 0 when creating the document")); .context("Revision's rev_id should be 0 when creating the document"));
} }
let delta = RichTextDelta::from_bytes(&revision.delta_data)?; let delta = TextDelta::from_bytes(&revision.delta_data)?;
let doc_json = delta.json_str(); let doc_json = delta.json_str();
Ok(DocumentPB { Ok(DocumentPB {

View File

@ -9,4 +9,4 @@ pub mod server_folder;
pub mod synchronizer; pub mod synchronizer;
pub mod util; pub mod util;
pub use lib_ot::rich_text::RichTextDelta; pub use lib_ot::text_delta::TextDelta;

View File

@ -11,7 +11,7 @@ use async_stream::stream;
use dashmap::DashMap; use dashmap::DashMap;
use futures::stream::StreamExt; use futures::stream::StreamExt;
use lib_infra::future::BoxResultFuture; use lib_infra::future::BoxResultFuture;
use lib_ot::rich_text::{RichTextDelta, TextAttributes}; use lib_ot::text_delta::{TextAttributes, TextDelta};
use std::{collections::HashMap, fmt::Debug, sync::Arc}; use std::{collections::HashMap, fmt::Debug, sync::Arc};
use tokio::{ use tokio::{
sync::{mpsc, oneshot, RwLock}, sync::{mpsc, oneshot, RwLock},
@ -212,7 +212,7 @@ impl OpenDocumentHandler {
let (sender, receiver) = mpsc::channel(1000); let (sender, receiver) = mpsc::channel(1000);
let users = DashMap::new(); let users = DashMap::new();
let delta = RichTextDelta::from_bytes(&doc.text)?; let delta = TextDelta::from_bytes(&doc.text)?;
let sync_object = ServerDocument::from_delta(&doc_id, delta); let sync_object = ServerDocument::from_delta(&doc_id, delta);
let synchronizer = Arc::new(DocumentRevisionSynchronizer::new(doc.rev_id, sync_object, persistence)); let synchronizer = Arc::new(DocumentRevisionSynchronizer::new(doc.rev_id, sync_object, persistence));

View File

@ -1,12 +1,12 @@
use crate::{client_document::InitialDocumentText, errors::CollaborateError, synchronizer::RevisionSyncObject}; use crate::{client_document::InitialDocumentText, errors::CollaborateError, synchronizer::RevisionSyncObject};
use lib_ot::{ use lib_ot::{
core::*, core::*,
rich_text::{RichTextDelta, TextAttributes}, text_delta::{TextAttributes, TextDelta},
}; };
pub struct ServerDocument { pub struct ServerDocument {
doc_id: String, doc_id: String,
delta: RichTextDelta, delta: TextDelta,
} }
impl ServerDocument { impl ServerDocument {
@ -15,7 +15,7 @@ impl ServerDocument {
Self::from_delta(doc_id, C::initial_delta()) Self::from_delta(doc_id, C::initial_delta())
} }
pub fn from_delta(doc_id: &str, delta: RichTextDelta) -> Self { pub fn from_delta(doc_id: &str, delta: TextDelta) -> Self {
let doc_id = doc_id.to_owned(); let doc_id = doc_id.to_owned();
ServerDocument { doc_id, delta } ServerDocument { doc_id, delta }
} }
@ -26,14 +26,14 @@ impl RevisionSyncObject<TextAttributes> for ServerDocument {
&self.doc_id &self.doc_id
} }
fn compose(&mut self, other: &RichTextDelta) -> Result<(), CollaborateError> { fn compose(&mut self, other: &TextDelta) -> Result<(), CollaborateError> {
// tracing::trace!("{} compose {}", &self.delta.to_json(), other.to_json()); // tracing::trace!("{} compose {}", &self.delta.to_json(), other.to_json());
let new_delta = self.delta.compose(other)?; let new_delta = self.delta.compose(other)?;
self.delta = new_delta; self.delta = new_delta;
Ok(()) Ok(())
} }
fn transform(&self, other: &RichTextDelta) -> Result<(RichTextDelta, RichTextDelta), CollaborateError> { fn transform(&self, other: &TextDelta) -> Result<(TextDelta, TextDelta), CollaborateError> {
let value = self.delta.transform(other)?; let value = self.delta.transform(other)?;
Ok(value) Ok(value)
} }
@ -42,7 +42,7 @@ impl RevisionSyncObject<TextAttributes> for ServerDocument {
self.delta.json_str() self.delta.json_str()
} }
fn set_delta(&mut self, new_delta: Delta<TextAttributes>) { fn set_delta(&mut self, new_delta: Operations<TextAttributes>) {
self.delta = new_delta; self.delta = new_delta;
} }
} }

View File

@ -13,7 +13,7 @@ use crate::{
use async_stream::stream; use async_stream::stream;
use futures::stream::StreamExt; use futures::stream::StreamExt;
use lib_infra::future::BoxResultFuture; use lib_infra::future::BoxResultFuture;
use lib_ot::core::PhantomAttributes; use lib_ot::core::EmptyAttributes;
use std::{collections::HashMap, fmt::Debug, sync::Arc}; use std::{collections::HashMap, fmt::Debug, sync::Arc};
use tokio::{ use tokio::{
sync::{mpsc, oneshot, RwLock}, sync::{mpsc, oneshot, RwLock},
@ -188,7 +188,7 @@ impl ServerFolderManager {
} }
} }
type FolderRevisionSynchronizer = RevisionSynchronizer<PhantomAttributes>; type FolderRevisionSynchronizer = RevisionSynchronizer<EmptyAttributes>;
struct OpenFolderHandler { struct OpenFolderHandler {
folder_id: String, folder_id: String,

View File

@ -1,5 +1,5 @@
use crate::{entities::folder::FolderDelta, errors::CollaborateError, synchronizer::RevisionSyncObject}; use crate::{entities::folder::FolderDelta, errors::CollaborateError, synchronizer::RevisionSyncObject};
use lib_ot::core::{OperationTransform, PhantomAttributes, TextDelta}; use lib_ot::core::{Delta, EmptyAttributes, OperationTransform};
pub struct ServerFolder { pub struct ServerFolder {
folder_id: String, folder_id: String,
@ -15,18 +15,18 @@ impl ServerFolder {
} }
} }
impl RevisionSyncObject<PhantomAttributes> for ServerFolder { impl RevisionSyncObject<EmptyAttributes> for ServerFolder {
fn id(&self) -> &str { fn id(&self) -> &str {
&self.folder_id &self.folder_id
} }
fn compose(&mut self, other: &TextDelta) -> Result<(), CollaborateError> { fn compose(&mut self, other: &Delta) -> Result<(), CollaborateError> {
let new_delta = self.delta.compose(other)?; let new_delta = self.delta.compose(other)?;
self.delta = new_delta; self.delta = new_delta;
Ok(()) Ok(())
} }
fn transform(&self, other: &TextDelta) -> Result<(TextDelta, TextDelta), CollaborateError> { fn transform(&self, other: &Delta) -> Result<(Delta, Delta), CollaborateError> {
let value = self.delta.transform(other)?; let value = self.delta.transform(other)?;
Ok(value) Ok(value)
} }
@ -35,7 +35,7 @@ impl RevisionSyncObject<PhantomAttributes> for ServerFolder {
self.delta.json_str() self.delta.json_str()
} }
fn set_delta(&mut self, new_delta: TextDelta) { fn set_delta(&mut self, new_delta: Delta) {
self.delta = new_delta; self.delta = new_delta;
} }
} }

View File

@ -9,7 +9,7 @@ use crate::{
util::*, util::*,
}; };
use lib_infra::future::BoxResultFuture; use lib_infra::future::BoxResultFuture;
use lib_ot::core::{Attributes, Delta}; use lib_ot::core::{Attributes, Operations};
use parking_lot::RwLock; use parking_lot::RwLock;
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use std::{ use std::{
@ -45,10 +45,10 @@ pub trait RevisionSyncPersistence: Send + Sync + 'static {
pub trait RevisionSyncObject<T: Attributes>: Send + Sync + 'static { pub trait RevisionSyncObject<T: Attributes>: Send + Sync + 'static {
fn id(&self) -> &str; fn id(&self) -> &str;
fn compose(&mut self, other: &Delta<T>) -> Result<(), CollaborateError>; fn compose(&mut self, other: &Operations<T>) -> Result<(), CollaborateError>;
fn transform(&self, other: &Delta<T>) -> Result<(Delta<T>, Delta<T>), CollaborateError>; fn transform(&self, other: &Operations<T>) -> Result<(Operations<T>, Operations<T>), CollaborateError>;
fn to_json(&self) -> String; fn to_json(&self) -> String;
fn set_delta(&mut self, new_delta: Delta<T>); fn set_delta(&mut self, new_delta: Operations<T>);
} }
pub enum RevisionSyncResponse { pub enum RevisionSyncResponse {
@ -183,20 +183,20 @@ where
} }
fn compose_revision(&self, revision: &Revision) -> Result<(), CollaborateError> { fn compose_revision(&self, revision: &Revision) -> Result<(), CollaborateError> {
let delta = Delta::<T>::from_bytes(&revision.delta_data)?; let delta = Operations::<T>::from_bytes(&revision.delta_data)?;
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));
Ok(()) Ok(())
} }
#[tracing::instrument(level = "debug", skip(self, revision))] #[tracing::instrument(level = "debug", skip(self, revision))]
fn transform_revision(&self, revision: &RevisionPB) -> Result<(Delta<T>, Delta<T>), CollaborateError> { fn transform_revision(&self, revision: &RevisionPB) -> Result<(Operations<T>, Operations<T>), CollaborateError> {
let cli_delta = Delta::<T>::from_bytes(&revision.delta_data)?; let cli_delta = Operations::<T>::from_bytes(&revision.delta_data)?;
let result = self.object.read().transform(&cli_delta)?; let result = self.object.read().transform(&cli_delta)?;
Ok(result) Ok(result)
} }
fn compose_delta(&self, delta: Delta<T>) -> Result<(), CollaborateError> { fn compose_delta(&self, delta: Operations<T>) -> Result<(), CollaborateError> {
if delta.is_empty() { if delta.is_empty() {
log::warn!("Composed delta is empty"); log::warn!("Composed delta is empty");
} }

View File

@ -7,10 +7,10 @@ use crate::{
errors::{CollaborateError, CollaborateResult}, errors::{CollaborateError, CollaborateResult},
}; };
use dissimilar::Chunk; use dissimilar::Chunk;
use lib_ot::core::{DeltaBuilder, OTString, PhantomAttributes, TextDelta}; use lib_ot::core::{Delta, EmptyAttributes, OTString, OperationBuilder};
use lib_ot::{ use lib_ot::{
core::{Attributes, Delta, OperationTransform, NEW_LINE, WHITESPACE}, core::{Attributes, OperationTransform, Operations, NEW_LINE, WHITESPACE},
rich_text::RichTextDelta, text_delta::TextDelta,
}; };
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use std::sync::atomic::{AtomicI64, Ordering::SeqCst}; use std::sync::atomic::{AtomicI64, Ordering::SeqCst};
@ -62,17 +62,17 @@ impl RevIdCounter {
} }
#[tracing::instrument(level = "trace", skip(revisions), err)] #[tracing::instrument(level = "trace", skip(revisions), err)]
pub fn make_delta_from_revisions<T>(revisions: Vec<Revision>) -> CollaborateResult<Delta<T>> pub fn make_delta_from_revisions<T>(revisions: Vec<Revision>) -> CollaborateResult<Operations<T>>
where where
T: Attributes + DeserializeOwned, T: Attributes + DeserializeOwned,
{ {
let mut delta = Delta::<T>::new(); let mut delta = Operations::<T>::new();
for revision in revisions { for revision in revisions {
if revision.delta_data.is_empty() { if revision.delta_data.is_empty() {
tracing::warn!("revision delta_data is empty"); tracing::warn!("revision delta_data is empty");
} }
let revision_delta = Delta::<T>::from_bytes(revision.delta_data).map_err(|e| { let revision_delta = Operations::<T>::from_bytes(revision.delta_data).map_err(|e| {
let err_msg = format!("Deserialize remote revision failed: {:?}", e); let err_msg = format!("Deserialize remote revision failed: {:?}", e);
CollaborateError::internal().context(err_msg) CollaborateError::internal().context(err_msg)
})?; })?;
@ -81,17 +81,17 @@ where
Ok(delta) Ok(delta)
} }
pub fn make_text_delta_from_revisions(revisions: Vec<Revision>) -> CollaborateResult<TextDelta> { pub fn make_text_delta_from_revisions(revisions: Vec<Revision>) -> CollaborateResult<Delta> {
make_delta_from_revisions::<PhantomAttributes>(revisions) make_delta_from_revisions::<EmptyAttributes>(revisions)
} }
pub fn make_delta_from_revision_pb<T>(revisions: Vec<Revision>) -> CollaborateResult<Delta<T>> pub fn make_delta_from_revision_pb<T>(revisions: Vec<Revision>) -> CollaborateResult<Operations<T>>
where where
T: Attributes + DeserializeOwned, T: Attributes + DeserializeOwned,
{ {
let mut new_delta = Delta::<T>::new(); let mut new_delta = Operations::<T>::new();
for revision in revisions { for revision in revisions {
let delta = Delta::<T>::from_bytes(revision.delta_data).map_err(|e| { let delta = Operations::<T>::from_bytes(revision.delta_data).map_err(|e| {
let err_msg = format!("Deserialize remote revision failed: {:?}", e); let err_msg = format!("Deserialize remote revision failed: {:?}", e);
CollaborateError::internal().context(err_msg) CollaborateError::internal().context(err_msg)
})?; })?;
@ -172,7 +172,7 @@ pub fn make_document_from_revision_pbs(
return Ok(None); return Ok(None);
} }
let mut delta = RichTextDelta::new(); let mut delta = TextDelta::new();
let mut base_rev_id = 0; let mut base_rev_id = 0;
let mut rev_id = 0; let mut rev_id = 0;
for revision in revisions { for revision in revisions {
@ -183,7 +183,7 @@ pub fn make_document_from_revision_pbs(
tracing::warn!("revision delta_data is empty"); tracing::warn!("revision delta_data is empty");
} }
let new_delta = RichTextDelta::from_bytes(revision.delta_data)?; let new_delta = TextDelta::from_bytes(revision.delta_data)?;
delta = delta.compose(&new_delta)?; delta = delta.compose(&new_delta)?;
} }
@ -206,9 +206,9 @@ pub fn rev_id_from_str(s: &str) -> Result<i64, CollaborateError> {
Ok(rev_id) Ok(rev_id)
} }
pub fn cal_diff<T: Attributes>(old: String, new: String) -> Option<Delta<T>> { pub fn cal_diff<T: Attributes>(old: String, new: String) -> Option<Operations<T>> {
let chunks = dissimilar::diff(&old, &new); let chunks = dissimilar::diff(&old, &new);
let mut delta_builder = DeltaBuilder::<T>::new(); let mut delta_builder = OperationBuilder::<T>::new();
for chunk in &chunks { for chunk in &chunks {
match chunk { match chunk {
Chunk::Equal(s) => { Chunk::Equal(s) => {

View File

@ -1,5 +1,5 @@
use crate::core::{Delta, DeltaIterator}; use crate::core::{OperationIterator, Operations};
use crate::rich_text::{is_block, TextAttributeKey, TextAttributeValue, TextAttributes}; use crate::text_delta::{is_block, TextAttributeKey, TextAttributeValue, TextAttributes};
use std::collections::HashMap; use std::collections::HashMap;
const LINEFEEDASCIICODE: i32 = 0x0A; const LINEFEEDASCIICODE: i32 = 0x0A;
@ -7,12 +7,12 @@ const LINEFEEDASCIICODE: i32 = 0x0A;
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::codec::markdown::markdown_encoder::markdown_encoder; use crate::codec::markdown::markdown_encoder::markdown_encoder;
use crate::rich_text::RichTextDelta; use crate::text_delta::TextDelta;
#[test] #[test]
fn markdown_encoder_header_1_test() { fn markdown_encoder_header_1_test() {
let json = r#"[{"insert":"header 1"},{"insert":"\n","attributes":{"header":1}}]"#; let json = r#"[{"insert":"header 1"},{"insert":"\n","attributes":{"header":1}}]"#;
let delta = RichTextDelta::from_json(json).unwrap(); let delta = TextDelta::from_json(json).unwrap();
let md = markdown_encoder(&delta); let md = markdown_encoder(&delta);
assert_eq!(md, "# header 1\n"); assert_eq!(md, "# header 1\n");
} }
@ -20,7 +20,7 @@ mod tests {
#[test] #[test]
fn markdown_encoder_header_2_test() { fn markdown_encoder_header_2_test() {
let json = r#"[{"insert":"header 2"},{"insert":"\n","attributes":{"header":2}}]"#; let json = r#"[{"insert":"header 2"},{"insert":"\n","attributes":{"header":2}}]"#;
let delta = RichTextDelta::from_json(json).unwrap(); let delta = TextDelta::from_json(json).unwrap();
let md = markdown_encoder(&delta); let md = markdown_encoder(&delta);
assert_eq!(md, "## header 2\n"); assert_eq!(md, "## header 2\n");
} }
@ -28,7 +28,7 @@ mod tests {
#[test] #[test]
fn markdown_encoder_header_3_test() { fn markdown_encoder_header_3_test() {
let json = r#"[{"insert":"header 3"},{"insert":"\n","attributes":{"header":3}}]"#; let json = r#"[{"insert":"header 3"},{"insert":"\n","attributes":{"header":3}}]"#;
let delta = RichTextDelta::from_json(json).unwrap(); let delta = TextDelta::from_json(json).unwrap();
let md = markdown_encoder(&delta); let md = markdown_encoder(&delta);
assert_eq!(md, "### header 3\n"); assert_eq!(md, "### header 3\n");
} }
@ -36,14 +36,14 @@ mod tests {
#[test] #[test]
fn markdown_encoder_bold_italics_underlined_test() { fn markdown_encoder_bold_italics_underlined_test() {
let json = r#"[{"insert":"bold","attributes":{"bold":true}},{"insert":" "},{"insert":"italics","attributes":{"italic":true}},{"insert":" "},{"insert":"underlined","attributes":{"underline":true}},{"insert":" "},{"insert":"\n","attributes":{"header":3}}]"#; let json = r#"[{"insert":"bold","attributes":{"bold":true}},{"insert":" "},{"insert":"italics","attributes":{"italic":true}},{"insert":" "},{"insert":"underlined","attributes":{"underline":true}},{"insert":" "},{"insert":"\n","attributes":{"header":3}}]"#;
let delta = RichTextDelta::from_json(json).unwrap(); let delta = TextDelta::from_json(json).unwrap();
let md = markdown_encoder(&delta); let md = markdown_encoder(&delta);
assert_eq!(md, "### **bold** _italics_ <u>underlined</u> \n"); assert_eq!(md, "### **bold** _italics_ <u>underlined</u> \n");
} }
#[test] #[test]
fn markdown_encoder_strikethrough_highlight_test() { fn markdown_encoder_strikethrough_highlight_test() {
let json = r##"[{"insert":"strikethrough","attributes":{"strike":true}},{"insert":" "},{"insert":"highlighted","attributes":{"background":"#ffefe3"}},{"insert":"\n"}]"##; let json = r##"[{"insert":"strikethrough","attributes":{"strike":true}},{"insert":" "},{"insert":"highlighted","attributes":{"background":"#ffefe3"}},{"insert":"\n"}]"##;
let delta = RichTextDelta::from_json(json).unwrap(); let delta = TextDelta::from_json(json).unwrap();
let md = markdown_encoder(&delta); let md = markdown_encoder(&delta);
assert_eq!(md, "~~strikethrough~~ <mark>highlighted</mark>\n"); assert_eq!(md, "~~strikethrough~~ <mark>highlighted</mark>\n");
} }
@ -51,7 +51,7 @@ mod tests {
#[test] #[test]
fn markdown_encoder_numbered_list_test() { fn markdown_encoder_numbered_list_test() {
let json = r#"[{"insert":"numbered list\nitem 1"},{"insert":"\n","attributes":{"list":"ordered"}},{"insert":"item 2"},{"insert":"\n","attributes":{"list":"ordered"}},{"insert":"item3"},{"insert":"\n","attributes":{"list":"ordered"}}]"#; let json = r#"[{"insert":"numbered list\nitem 1"},{"insert":"\n","attributes":{"list":"ordered"}},{"insert":"item 2"},{"insert":"\n","attributes":{"list":"ordered"}},{"insert":"item3"},{"insert":"\n","attributes":{"list":"ordered"}}]"#;
let delta = RichTextDelta::from_json(json).unwrap(); let delta = TextDelta::from_json(json).unwrap();
let md = markdown_encoder(&delta); let md = markdown_encoder(&delta);
assert_eq!(md, "numbered list\n\n1. item 1\n1. item 2\n1. item3\n"); assert_eq!(md, "numbered list\n\n1. item 1\n1. item 2\n1. item3\n");
} }
@ -59,7 +59,7 @@ mod tests {
#[test] #[test]
fn markdown_encoder_bullet_list_test() { fn markdown_encoder_bullet_list_test() {
let json = r#"[{"insert":"bullet list\nitem1"},{"insert":"\n","attributes":{"list":"bullet"}}]"#; let json = r#"[{"insert":"bullet list\nitem1"},{"insert":"\n","attributes":{"list":"bullet"}}]"#;
let delta = RichTextDelta::from_json(json).unwrap(); let delta = TextDelta::from_json(json).unwrap();
let md = markdown_encoder(&delta); let md = markdown_encoder(&delta);
assert_eq!(md, "bullet list\n\n* item1\n"); assert_eq!(md, "bullet list\n\n* item1\n");
} }
@ -67,7 +67,7 @@ mod tests {
#[test] #[test]
fn markdown_encoder_check_list_test() { fn markdown_encoder_check_list_test() {
let json = r#"[{"insert":"check list\nchecked"},{"insert":"\n","attributes":{"list":"checked"}},{"insert":"unchecked"},{"insert":"\n","attributes":{"list":"unchecked"}}]"#; let json = r#"[{"insert":"check list\nchecked"},{"insert":"\n","attributes":{"list":"checked"}},{"insert":"unchecked"},{"insert":"\n","attributes":{"list":"unchecked"}}]"#;
let delta = RichTextDelta::from_json(json).unwrap(); let delta = TextDelta::from_json(json).unwrap();
let md = markdown_encoder(&delta); let md = markdown_encoder(&delta);
assert_eq!(md, "check list\n\n- [x] checked\n\n- [ ] unchecked\n"); assert_eq!(md, "check list\n\n- [x] checked\n\n- [ ] unchecked\n");
} }
@ -75,7 +75,7 @@ mod tests {
#[test] #[test]
fn markdown_encoder_code_test() { fn markdown_encoder_code_test() {
let json = r#"[{"insert":"code this "},{"insert":"print(\"hello world\")","attributes":{"code":true}},{"insert":"\n"}]"#; let json = r#"[{"insert":"code this "},{"insert":"print(\"hello world\")","attributes":{"code":true}},{"insert":"\n"}]"#;
let delta = RichTextDelta::from_json(json).unwrap(); let delta = TextDelta::from_json(json).unwrap();
let md = markdown_encoder(&delta); let md = markdown_encoder(&delta);
assert_eq!(md, "code this `print(\"hello world\")`\n"); assert_eq!(md, "code this `print(\"hello world\")`\n");
} }
@ -83,7 +83,7 @@ mod tests {
#[test] #[test]
fn markdown_encoder_quote_block_test() { fn markdown_encoder_quote_block_test() {
let json = r#"[{"insert":"this is a quote block"},{"insert":"\n","attributes":{"blockquote":true}}]"#; let json = r#"[{"insert":"this is a quote block"},{"insert":"\n","attributes":{"blockquote":true}}]"#;
let delta = RichTextDelta::from_json(json).unwrap(); let delta = TextDelta::from_json(json).unwrap();
let md = markdown_encoder(&delta); let md = markdown_encoder(&delta);
assert_eq!(md, "> this is a quote block\n"); assert_eq!(md, "> this is a quote block\n");
} }
@ -91,7 +91,7 @@ mod tests {
#[test] #[test]
fn markdown_encoder_link_test() { fn markdown_encoder_link_test() {
let json = r#"[{"insert":"appflowy","attributes":{"link":"https://www.appflowy.io/"}},{"insert":"\n"}]"#; let json = r#"[{"insert":"appflowy","attributes":{"link":"https://www.appflowy.io/"}},{"insert":"\n"}]"#;
let delta = RichTextDelta::from_json(json).unwrap(); let delta = TextDelta::from_json(json).unwrap();
let md = markdown_encoder(&delta); let md = markdown_encoder(&delta);
assert_eq!(md, "[appflowy](https://www.appflowy.io/)\n"); assert_eq!(md, "[appflowy](https://www.appflowy.io/)\n");
} }
@ -102,12 +102,12 @@ struct Attribute {
value: TextAttributeValue, value: TextAttributeValue,
} }
pub fn markdown_encoder(delta: &Delta<TextAttributes>) -> String { pub fn markdown_encoder(delta: &Operations<TextAttributes>) -> String {
let mut markdown_buffer = String::new(); let mut markdown_buffer = String::new();
let mut line_buffer = String::new(); let mut line_buffer = String::new();
let mut current_inline_style = TextAttributes::default(); let mut current_inline_style = TextAttributes::default();
let mut current_block_lines: Vec<String> = Vec::new(); let mut current_block_lines: Vec<String> = Vec::new();
let mut iterator = DeltaIterator::new(delta); let mut iterator = OperationIterator::new(delta);
let mut current_block_style: Option<Attribute> = None; let mut current_block_style: Option<Attribute> = None;
while iterator.has_next() { while iterator.has_next() {

View File

@ -1,8 +1,8 @@
use crate::core::delta::{trim, Delta}; use crate::core::delta::operation::Attributes;
use crate::core::operation::Attributes; use crate::core::delta::{trim, Operations};
use crate::core::Operation; use crate::core::Operation;
/// A builder for creating new [Delta] objects. /// A builder for creating new [Operations] objects.
/// ///
/// Note that all edit operations must be sorted; the start point of each /// Note that all edit operations must be sorted; the start point of each
/// interval must be no less than the end point of the previous one. /// interval must be no less than the end point of the previous one.
@ -10,35 +10,37 @@ use crate::core::Operation;
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use lib_ot::core::TextDeltaBuilder; /// use lib_ot::core::DeltaBuilder;
/// let delta = TextDeltaBuilder::new() /// let delta = DeltaBuilder::new()
/// .insert("AppFlowy") /// .insert("AppFlowy")
/// .build(); /// .build();
/// assert_eq!(delta.content().unwrap(), "AppFlowy"); /// assert_eq!(delta.content().unwrap(), "AppFlowy");
/// ``` /// ```
pub struct DeltaBuilder<T: Attributes> { pub struct OperationBuilder<T: Attributes> {
delta: Delta<T>, delta: Operations<T>,
} }
impl<T> std::default::Default for DeltaBuilder<T> impl<T> std::default::Default for OperationBuilder<T>
where where
T: Attributes, T: Attributes,
{ {
fn default() -> Self { fn default() -> Self {
Self { delta: Delta::new() } Self {
delta: Operations::new(),
}
} }
} }
impl<T> DeltaBuilder<T> impl<T> OperationBuilder<T>
where where
T: Attributes, T: Attributes,
{ {
pub fn new() -> Self { pub fn new() -> Self {
DeltaBuilder::default() OperationBuilder::default()
} }
pub fn from_operations(operations: Vec<Operation<T>>) -> Delta<T> { pub fn from_operations(operations: Vec<Operation<T>>) -> Operations<T> {
let mut delta = DeltaBuilder::default().build(); let mut delta = OperationBuilder::default().build();
operations.into_iter().for_each(|operation| { operations.into_iter().for_each(|operation| {
delta.add(operation); delta.add(operation);
}); });
@ -50,10 +52,10 @@ where
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use lib_ot::rich_text::{TextAttribute, RichTextDelta, RichTextDeltaBuilder}; /// use lib_ot::text_delta::{TextAttribute, TextDelta, TextDeltaBuilder};
/// ///
/// let mut attribute = TextAttribute::Bold(true); /// let mut attribute = TextAttribute::Bold(true);
/// let delta = RichTextDeltaBuilder::new().retain_with_attributes(7, attribute.into()).build(); /// let delta = TextDeltaBuilder::new().retain_with_attributes(7, attribute.into()).build();
/// ///
/// assert_eq!(delta.json_str(), r#"[{"retain":7,"attributes":{"bold":true}}]"#); /// assert_eq!(delta.json_str(), r#"[{"retain":7,"attributes":{"bold":true}}]"#);
/// ``` /// ```
@ -72,13 +74,13 @@ where
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use lib_ot::core::{OperationTransform, TextDeltaBuilder}; /// use lib_ot::core::{OperationTransform, DeltaBuilder};
/// ///
/// let delta = TextDeltaBuilder::new() /// let delta = DeltaBuilder::new()
/// .insert("AppFlowy...") /// .insert("AppFlowy...")
/// .build(); /// .build();
/// ///
/// let changeset = TextDeltaBuilder::new() /// let changeset = DeltaBuilder::new()
/// .retain(8) /// .retain(8)
/// .delete(3) /// .delete(3)
/// .build(); /// .build();
@ -108,15 +110,15 @@ where
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use lib_ot::core::{OperationTransform, TextDeltaBuilder}; /// use lib_ot::core::{OperationTransform, DeltaBuilder};
/// use lib_ot::rich_text::{TextAttribute, RichTextDeltaBuilder}; /// use lib_ot::text_delta::{TextAttribute, TextDeltaBuilder};
/// let delta = TextDeltaBuilder::new() /// let delta = DeltaBuilder::new()
/// .retain(3) /// .retain(3)
/// .trim() /// .trim()
/// .build(); /// .build();
/// assert_eq!(delta.ops.len(), 0); /// assert_eq!(delta.ops.len(), 0);
/// ///
/// let delta = RichTextDeltaBuilder::new() /// let delta = TextDeltaBuilder::new()
/// .retain_with_attributes(3, TextAttribute::Bold(true).into()) /// .retain_with_attributes(3, TextAttribute::Bold(true).into())
/// .trim() /// .trim()
/// .build(); /// .build();
@ -128,7 +130,7 @@ where
} }
/// Builds the `Delta` /// Builds the `Delta`
pub fn build(self) -> Delta<T> { pub fn build(self) -> Operations<T> {
self.delta self.delta
} }
} }

View File

@ -1,14 +1,14 @@
#![allow(clippy::while_let_on_iterator)] #![allow(clippy::while_let_on_iterator)]
use crate::core::delta::Delta; use crate::core::delta::operation::{Attributes, Operation};
use crate::core::delta::Operations;
use crate::core::interval::Interval; use crate::core::interval::Interval;
use crate::core::operation::{Attributes, Operation};
use crate::errors::{ErrorBuilder, OTError, OTErrorCode}; use crate::errors::{ErrorBuilder, OTError, OTErrorCode};
use std::{cmp::min, iter::Enumerate, slice::Iter}; use std::{cmp::min, iter::Enumerate, slice::Iter};
/// A [DeltaCursor] is used to iterate the delta and return the corresponding delta. /// A [OperationsCursor] is used to iterate the delta and return the corresponding delta.
#[derive(Debug)] #[derive(Debug)]
pub struct DeltaCursor<'a, T: Attributes> { pub struct OperationsCursor<'a, T: Attributes> {
pub(crate) delta: &'a Delta<T>, pub(crate) delta: &'a Operations<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,
@ -17,7 +17,7 @@ pub struct DeltaCursor<'a, T: Attributes> {
next_op: Option<Operation<T>>, next_op: Option<Operation<T>>,
} }
impl<'a, T> DeltaCursor<'a, T> impl<'a, T> OperationsCursor<'a, T>
where where
T: Attributes, T: Attributes,
{ {
@ -29,19 +29,19 @@ where
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use lib_ot::core::{DeltaCursor, DeltaIterator, Interval, Operation}; /// use lib_ot::core::{OperationsCursor, OperationIterator, Interval, Operation};
/// use lib_ot::rich_text::RichTextDelta; /// use lib_ot::text_delta::TextDelta;
/// let mut delta = RichTextDelta::default(); /// let mut delta = TextDelta::default();
/// delta.add(Operation::insert("123")); /// delta.add(Operation::insert("123"));
/// delta.add(Operation::insert("4")); /// delta.add(Operation::insert("4"));
/// ///
/// let mut cursor = DeltaCursor::new(&delta, Interval::new(0, 3)); /// let mut cursor = OperationsCursor::new(&delta, Interval::new(0, 3));
/// assert_eq!(cursor.next_iv(), Interval::new(0,3)); /// assert_eq!(cursor.next_iv(), Interval::new(0,3));
/// assert_eq!(cursor.next_with_len(Some(2)).unwrap(), Operation::insert("12")); /// assert_eq!(cursor.next_with_len(Some(2)).unwrap(), Operation::insert("12"));
/// assert_eq!(cursor.get_next_op().unwrap(), Operation::insert("3")); /// assert_eq!(cursor.get_next_op().unwrap(), Operation::insert("3"));
/// assert_eq!(cursor.get_next_op(), None); /// assert_eq!(cursor.get_next_op(), None);
/// ``` /// ```
pub fn new(delta: &'a Delta<T>, interval: Interval) -> DeltaCursor<'a, T> { pub fn new(delta: &'a Operations<T>, interval: Interval) -> OperationsCursor<'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,
@ -182,7 +182,7 @@ where
} }
} }
fn find_next<'a, T>(cursor: &mut DeltaCursor<'a, T>) -> Option<&'a Operation<T>> fn find_next<'a, T>(cursor: &mut OperationsCursor<'a, T>) -> Option<&'a Operation<T>>
where where
T: Attributes, T: Attributes,
{ {
@ -197,7 +197,7 @@ where
type SeekResult = Result<(), OTError>; type SeekResult = Result<(), OTError>;
pub trait Metric { pub trait Metric {
fn seek<T: Attributes>(cursor: &mut DeltaCursor<T>, offset: usize) -> SeekResult; fn seek<T: Attributes>(cursor: &mut OperationsCursor<T>, offset: usize) -> SeekResult;
} }
/// [OpMetric] is used by [DeltaIterator] for seeking operations /// [OpMetric] is used by [DeltaIterator] for seeking operations
@ -205,9 +205,9 @@ pub trait Metric {
pub struct OpMetric(); pub struct OpMetric();
impl Metric for OpMetric { impl Metric for OpMetric {
fn seek<T: Attributes>(cursor: &mut DeltaCursor<T>, op_offset: usize) -> SeekResult { fn seek<T: Attributes>(cursor: &mut OperationsCursor<T>, op_offset: usize) -> SeekResult {
let _ = check_bound(cursor.op_offset, op_offset)?; let _ = check_bound(cursor.op_offset, op_offset)?;
let mut seek_cursor = DeltaCursor::new(cursor.delta, cursor.origin_iv); let mut seek_cursor = OperationsCursor::new(cursor.delta, cursor.origin_iv);
while let Some((_, op)) = seek_cursor.iter.next() { while let Some((_, op)) = seek_cursor.iter.next() {
cursor.descend(op.len()); cursor.descend(op.len());
@ -219,12 +219,12 @@ impl Metric for OpMetric {
} }
} }
/// [Utf16CodeUnitMetric] is used by [DeltaIterator] for seeking operations. /// [Utf16CodeUnitMetric] is used by [OperationIterator] for seeking operations.
/// The unit of the movement is Utf16CodeUnit /// The unit of the movement is Utf16CodeUnit
pub struct Utf16CodeUnitMetric(); pub struct Utf16CodeUnitMetric();
impl Metric for Utf16CodeUnitMetric { impl Metric for Utf16CodeUnitMetric {
fn seek<T: Attributes>(cursor: &mut DeltaCursor<T>, offset: usize) -> SeekResult { fn seek<T: Attributes>(cursor: &mut OperationsCursor<T>, offset: usize) -> SeekResult {
if offset > 0 { if offset > 0 {
let _ = check_bound(cursor.consume_count, offset)?; let _ = check_bound(cursor.consume_count, offset)?;
let _ = cursor.next_with_len(Some(offset)); let _ = cursor.next_with_len(Some(offset));

View File

@ -1,55 +1,55 @@
use super::cursor::*; use super::cursor::*;
use crate::core::delta::{Delta, NEW_LINE}; use crate::core::delta::operation::{Attributes, Operation};
use crate::core::delta::{Operations, NEW_LINE};
use crate::core::interval::Interval; use crate::core::interval::Interval;
use crate::core::operation::{Attributes, Operation}; use crate::text_delta::TextAttributes;
use crate::rich_text::TextAttributes;
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;
/// [DeltaIterator] is used to iterate over a delta. /// [OperationIterator] is used to iterate over the operations.
/// # Examples /// # Examples
/// ///
/// You could check [this](https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/architecture/backend/delta) out for more information. /// You could check [this](https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/architecture/backend/delta) out for more information.
/// ///
/// ``` /// ```
/// use lib_ot::core::{DeltaIterator, Interval, Operation}; /// use lib_ot::core::{OperationIterator, Interval, Operation};
/// use lib_ot::rich_text::RichTextDelta; /// use lib_ot::text_delta::TextDelta;
/// let mut delta = RichTextDelta::default(); /// let mut delta = TextDelta::default();
/// delta.add(Operation::insert("123")); /// delta.add(Operation::insert("123"));
/// delta.add(Operation::insert("4")); /// delta.add(Operation::insert("4"));
/// assert_eq!( /// assert_eq!(
/// DeltaIterator::from_interval(&delta, Interval::new(0, 2)).ops(), /// OperationIterator::from_interval(&delta, Interval::new(0, 2)).ops(),
/// vec![Operation::insert("12")] /// vec![Operation::insert("12")]
/// ); /// );
/// ///
/// assert_eq!( /// assert_eq!(
/// DeltaIterator::from_interval(&delta, Interval::new(1, 3)).ops(), /// OperationIterator::from_interval(&delta, Interval::new(1, 3)).ops(),
/// vec![Operation::insert("23")] /// vec![Operation::insert("23")]
/// ); /// );
/// ``` /// ```
pub struct DeltaIterator<'a, T: Attributes> { pub struct OperationIterator<'a, T: Attributes> {
cursor: DeltaCursor<'a, T>, cursor: OperationsCursor<'a, T>,
} }
impl<'a, T> DeltaIterator<'a, T> impl<'a, T> OperationIterator<'a, T>
where where
T: Attributes, T: Attributes,
{ {
pub fn new(delta: &'a Delta<T>) -> Self { pub fn new(delta: &'a Operations<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<T>, offset: usize) -> Self { pub fn from_offset(delta: &'a Operations<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::<Utf16CodeUnitMetric>(offset); iter.seek::<Utf16CodeUnitMetric>(offset);
iter iter
} }
pub fn from_interval(delta: &'a Delta<T>, interval: Interval) -> Self { pub fn from_interval(delta: &'a Operations<T>, interval: Interval) -> Self {
let cursor = DeltaCursor::new(delta, interval); let cursor = OperationsCursor::new(delta, interval);
Self { cursor } Self { cursor }
} }
@ -122,7 +122,7 @@ where
} }
} }
impl<'a, T> Iterator for DeltaIterator<'a, T> impl<'a, T> Iterator for OperationIterator<'a, T>
where where
T: Attributes, T: Attributes,
{ {
@ -132,8 +132,8 @@ where
} }
} }
pub fn is_empty_line_at_index(delta: &Delta<TextAttributes>, index: usize) -> bool { pub fn is_empty_line_at_index(delta: &Operations<TextAttributes>, index: usize) -> bool {
let mut iter = DeltaIterator::new(delta); let mut iter = OperationIterator::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() {
return true; return true;
@ -149,20 +149,20 @@ pub fn is_empty_line_at_index(delta: &Delta<TextAttributes>, index: usize) -> bo
} }
pub struct AttributesIter<'a, T: Attributes> { pub struct AttributesIter<'a, T: Attributes> {
delta_iter: DeltaIterator<'a, T>, delta_iter: OperationIterator<'a, T>,
} }
impl<'a, T> AttributesIter<'a, T> impl<'a, T> AttributesIter<'a, T>
where where
T: Attributes, T: Attributes,
{ {
pub fn new(delta: &'a Delta<T>) -> Self { pub fn new(delta: &'a Operations<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<T>, interval: Interval) -> Self { pub fn from_interval(delta: &'a Operations<T>, interval: Interval) -> Self {
let delta_iter = DeltaIterator::from_interval(delta, interval); let delta_iter = OperationIterator::from_interval(delta, interval);
Self { delta_iter } Self { delta_iter }
} }
@ -178,7 +178,7 @@ impl<'a, T> Deref for AttributesIter<'a, T>
where where
T: Attributes, T: Attributes,
{ {
type Target = DeltaIterator<'a, T>; type Target = OperationIterator<'a, T>;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.delta_iter &self.delta_iter

View File

@ -1,14 +1,15 @@
#![allow(clippy::module_inception)] #![allow(clippy::module_inception)]
mod builder; mod builder;
mod cursor; mod cursor;
mod delta;
mod delta_serde;
mod iterator; mod iterator;
pub mod operation;
mod ops;
mod ops_serde;
pub use builder::*; pub use builder::*;
pub use cursor::*; pub use cursor::*;
pub use delta::*;
pub use iterator::*; pub use iterator::*;
pub use ops::*;
pub const NEW_LINE: &str = "\n"; pub const NEW_LINE: &str = "\n";
pub const WHITESPACE: &str = " "; pub const WHITESPACE: &str = " ";

View File

@ -1,8 +1,8 @@
use crate::core::operation::{Attributes, Operation, PhantomAttributes}; use crate::core::delta::operation::{Attributes, EmptyAttributes, Operation};
use crate::rich_text::TextAttributes; use crate::text_delta::TextAttributes;
pub type RichTextOpBuilder = OperationsBuilder<TextAttributes>; pub type RichTextOpBuilder = OperationsBuilder<TextAttributes>;
pub type PlainTextOpBuilder = OperationsBuilder<PhantomAttributes>; pub type PlainTextOpBuilder = OperationsBuilder<EmptyAttributes>;
#[derive(Default)] #[derive(Default)]
pub struct OperationsBuilder<T: Attributes> { pub struct OperationsBuilder<T: Attributes> {

View File

@ -21,10 +21,10 @@ pub trait OperationTransform {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use lib_ot::core::{OperationTransform, TextDeltaBuilder}; /// use lib_ot::core::{OperationTransform, DeltaBuilder};
/// let document = TextDeltaBuilder::new().build(); /// let delta = DeltaBuilder::new().build();
/// let delta = TextDeltaBuilder::new().insert("abc").build(); /// let other = DeltaBuilder::new().insert("abc").build();
/// let new_document = document.compose(&delta).unwrap(); /// let new_document = delta.compose(&other).unwrap();
/// assert_eq!(new_document.content().unwrap(), "abc".to_owned()); /// assert_eq!(new_document.content().unwrap(), "abc".to_owned());
/// ``` /// ```
fn compose(&self, other: &Self) -> Result<Self, OTError> fn compose(&self, other: &Self) -> Result<Self, OTError>
@ -50,15 +50,15 @@ pub trait OperationTransform {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use lib_ot::core::{OperationTransform, TextDeltaBuilder}; /// use lib_ot::core::{OperationTransform, DeltaBuilder};
/// let original_document = TextDeltaBuilder::new().build(); /// let initial_delta = DeltaBuilder::new().build();
/// let delta = TextDeltaBuilder::new().insert("abc").build(); /// let delta = DeltaBuilder::new().insert("abc").build();
/// ///
/// let undo_delta = delta.invert(&original_document); /// let undo_delta = delta.invert(&initial_delta);
/// let new_document = original_document.compose(&delta).unwrap(); /// let composed_delta = initial_delta.compose(&delta).unwrap();
/// let document = new_document.compose(&undo_delta).unwrap(); /// let inverted_delta = composed_delta.compose(&undo_delta).unwrap();
/// ///
/// assert_eq!(original_document, document); /// assert_eq!(initial_delta, inverted_delta);
/// ///
/// ``` /// ```
fn invert(&self, other: &Self) -> Self; fn invert(&self, other: &Self) -> Self;
@ -67,8 +67,8 @@ pub trait OperationTransform {
/// Each operation can carry attributes. For example, the [TextAttributes] has a list of key/value attributes. /// Each operation can carry attributes. For example, the [TextAttributes] has a list of key/value attributes.
/// Such as { bold: true, italic: true }. /// Such as { bold: true, italic: true }.
/// ///
///Because [Operation] is generic over the T, so you must specify the T. For example, the [TextDelta] uses ///Because [Operation] is generic over the T, so you must specify the T. For example, the [Delta] uses
///[PhantomAttributes] as the T. [PhantomAttributes] does nothing, just a phantom. ///[EmptyAttributes] as the T. [EmptyAttributes] does nothing, just a phantom.
/// ///
pub trait Attributes: Default + Display + Eq + PartialEq + Clone + Debug + OperationTransform { pub trait Attributes: Default + Display + Eq + PartialEq + Clone + Debug + OperationTransform {
fn is_empty(&self) -> bool { fn is_empty(&self) -> bool {
@ -218,8 +218,8 @@ where
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use lib_ot::core::{Interval, Operation, PhantomAttributes}; /// use lib_ot::core::{Interval, Operation, EmptyAttributes};
/// let operation = Operation::<PhantomAttributes>::insert("1234"); /// let operation = Operation::<EmptyAttributes>::insert("1234");
/// ///
/// let op1 = operation.shrink(Interval::new(0,3)).unwrap(); /// let op1 = operation.shrink(Interval::new(0,3)).unwrap();
/// assert_eq!(op1 , Operation::insert("123")); /// assert_eq!(op1 , Operation::insert("123"));
@ -459,16 +459,16 @@ where
} }
#[derive(Debug, Clone, Eq, PartialEq, Default, Serialize, Deserialize)] #[derive(Debug, Clone, Eq, PartialEq, Default, Serialize, Deserialize)]
pub struct PhantomAttributes(); pub struct EmptyAttributes();
impl fmt::Display for PhantomAttributes { impl fmt::Display for EmptyAttributes {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("PhantomAttributes") f.write_str("PhantomAttributes")
} }
} }
impl Attributes for PhantomAttributes {} impl Attributes for EmptyAttributes {}
impl OperationTransform for PhantomAttributes { impl OperationTransform for EmptyAttributes {
fn compose(&self, _other: &Self) -> Result<Self, OTError> { fn compose(&self, _other: &Self) -> Result<Self, OTError> {
Ok(self.clone()) Ok(self.clone())
} }

View File

@ -1,4 +1,4 @@
use crate::core::operation::{Attributes, Insert, Operation, Retain}; use crate::core::delta::operation::{Attributes, Insert, Operation, Retain};
use crate::core::ot_str::OTString; use crate::core::ot_str::OTString;
use serde::{ use serde::{
de, de,

View File

@ -1,10 +1,10 @@
use crate::errors::{ErrorBuilder, OTError, OTErrorCode}; use crate::errors::{ErrorBuilder, OTError, OTErrorCode};
use crate::core::delta::{DeltaIterator, MAX_IV_LEN}; use crate::core::delta::operation::{Attributes, EmptyAttributes, Operation, OperationTransform};
use crate::core::delta::{OperationIterator, MAX_IV_LEN};
use crate::core::interval::Interval; use crate::core::interval::Interval;
use crate::core::operation::{Attributes, Operation, OperationTransform, PhantomAttributes};
use crate::core::ot_str::OTString; use crate::core::ot_str::OTString;
use crate::core::DeltaBuilder; use crate::core::OperationBuilder;
use bytes::Bytes; use bytes::Bytes;
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use std::{ use std::{
@ -15,8 +15,8 @@ use std::{
str::FromStr, str::FromStr,
}; };
pub type TextDelta = Delta<PhantomAttributes>; pub type Delta = Operations<EmptyAttributes>;
pub type TextDeltaBuilder = DeltaBuilder<PhantomAttributes>; pub type DeltaBuilder = OperationBuilder<EmptyAttributes>;
/// A [Delta] contains list of operations that consists of 'Retain', 'Delete' and 'Insert' operation. /// A [Delta] contains list of operations that consists of 'Retain', 'Delete' and 'Insert' operation.
/// Check out the [Operation] for more details. It describes the document as a sequence of /// Check out the [Operation] for more details. It describes the document as a sequence of
@ -28,7 +28,7 @@ pub type TextDeltaBuilder = DeltaBuilder<PhantomAttributes>;
/// a JSON string. /// a JSON string.
/// ///
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
pub struct Delta<T: Attributes> { pub struct Operations<T: Attributes> {
pub ops: Vec<Operation<T>>, pub ops: Vec<Operation<T>>,
/// 'Delete' and 'Retain' operation will update the [utf16_base_len] /// 'Delete' and 'Retain' operation will update the [utf16_base_len]
@ -40,7 +40,7 @@ pub struct Delta<T: Attributes> {
pub utf16_target_len: usize, pub utf16_target_len: usize,
} }
impl<T> Default for Delta<T> impl<T> Default for Operations<T>
where where
T: Attributes, T: Attributes,
{ {
@ -53,7 +53,7 @@ where
} }
} }
impl<T> fmt::Display for Delta<T> impl<T> fmt::Display for Operations<T>
where where
T: Attributes, T: Attributes,
{ {
@ -68,12 +68,12 @@ where
} }
} }
impl<T> FromIterator<Operation<T>> for Delta<T> impl<T> FromIterator<Operation<T>> for Operations<T>
where where
T: Attributes, T: Attributes,
{ {
fn from_iter<I: IntoIterator<Item = Operation<T>>>(ops: I) -> Self { fn from_iter<I: IntoIterator<Item = Operation<T>>>(ops: I) -> Self {
let mut operations = Delta::default(); let mut operations = Operations::default();
for op in ops { for op in ops {
operations.add(op); operations.add(op);
} }
@ -81,7 +81,7 @@ where
} }
} }
impl<T> Delta<T> impl<T> Operations<T>
where where
T: Attributes, T: Attributes,
{ {
@ -180,10 +180,10 @@ where
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use lib_ot::core::TextDeltaBuilder; /// use lib_ot::core::DeltaBuilder;
/// let s = "hello"; /// let s = "hello";
/// let delta_a = TextDeltaBuilder::new().insert(s).build(); /// let delta_a = DeltaBuilder::new().insert(s).build();
/// let delta_b = TextDeltaBuilder::new() /// let delta_b = DeltaBuilder::new()
/// .retain(s.len()) /// .retain(s.len())
/// .insert(", AppFlowy") /// .insert(", AppFlowy")
/// .build(); /// .build();
@ -237,9 +237,9 @@ where
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use lib_ot::core::TextDeltaBuilder; /// use lib_ot::core::DeltaBuilder;
/// let s = "hello world"; /// let s = "hello world";
/// let delta = TextDeltaBuilder::new().insert(s).build(); /// let delta = DeltaBuilder::new().insert(s).build();
/// let invert_delta = delta.invert_str(s); /// let invert_delta = delta.invert_str(s);
/// assert_eq!(delta.utf16_base_len, invert_delta.utf16_target_len); /// assert_eq!(delta.utf16_base_len, invert_delta.utf16_target_len);
/// assert_eq!(delta.utf16_target_len, invert_delta.utf16_base_len); /// assert_eq!(delta.utf16_target_len, invert_delta.utf16_base_len);
@ -249,7 +249,7 @@ where
/// ``` /// ```
/// ///
pub fn invert_str(&self, inverted_s: &str) -> Self { pub fn invert_str(&self, inverted_s: &str) -> Self {
let mut inverted = Delta::default(); let mut inverted = Operations::default();
let inverted_s: OTString = inverted_s.into(); let inverted_s: OTString = inverted_s.into();
let code_point_iter = &mut inverted_s.utf16_iter(); let code_point_iter = &mut inverted_s.utf16_iter();
@ -292,7 +292,7 @@ where
} }
} }
impl<T> OperationTransform for Delta<T> impl<T> OperationTransform for Operations<T>
where where
T: Attributes, T: Attributes,
{ {
@ -300,9 +300,9 @@ where
where where
Self: Sized, Self: Sized,
{ {
let mut new_delta = Delta::default(); let mut new_delta = Operations::default();
let mut iter = DeltaIterator::new(self); let mut iter = OperationIterator::new(self);
let mut other_iter = DeltaIterator::new(other); let mut other_iter = OperationIterator::new(other);
while iter.has_next() || other_iter.has_next() { while iter.has_next() || other_iter.has_next() {
if other_iter.is_next_insert() { if other_iter.is_next_insert() {
@ -366,8 +366,8 @@ where
.build()); .build());
} }
let mut a_prime = Delta::default(); let mut a_prime = Operations::default();
let mut b_prime = Delta::default(); let mut b_prime = Operations::default();
let mut ops1 = self.ops.iter().cloned(); let mut ops1 = self.ops.iter().cloned();
let mut ops2 = other.ops.iter().cloned(); let mut ops2 = other.ops.iter().cloned();
@ -476,7 +476,7 @@ where
} }
fn invert(&self, other: &Self) -> Self { fn invert(&self, other: &Self) -> Self {
let mut inverted = Delta::default(); let mut inverted = Operations::default();
let mut index = 0; let mut index = 0;
for op in &self.ops { for op in &self.ops {
let len: usize = op.len() as usize; let len: usize = op.len() as usize;
@ -507,7 +507,7 @@ where
} }
/// Removes trailing retain operation with empty attributes, if present. /// Removes trailing retain operation with empty attributes, if present.
pub fn trim<T>(delta: &mut Delta<T>) pub fn trim<T>(delta: &mut Operations<T>)
where where
T: Attributes, T: Attributes,
{ {
@ -519,14 +519,14 @@ where
} }
fn invert_other<T: Attributes>( fn invert_other<T: Attributes>(
base: &mut Delta<T>, base: &mut Operations<T>,
other: &Delta<T>, other: &Operations<T>,
operation: &Operation<T>, operation: &Operation<T>,
start: usize, start: usize,
end: usize, end: usize,
) { ) {
tracing::trace!("invert op: {} [{}:{}]", operation, start, end); tracing::trace!("invert op: {} [{}:{}]", operation, start, end);
let other_ops = DeltaIterator::from_interval(other, Interval::new(start, end)).ops(); let other_ops = OperationIterator::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 {
Operation::Delete(_n) => { Operation::Delete(_n) => {
// tracing::trace!("invert delete: {} by add {}", n, other_op); // tracing::trace!("invert delete: {} by add {}", n, other_op);
@ -563,19 +563,19 @@ fn transform_op_attribute<T: Attributes>(
Ok(left.transform(&right)?.0) Ok(left.transform(&right)?.0)
} }
impl<T> Delta<T> impl<T> Operations<T>
where where
T: Attributes + DeserializeOwned, T: Attributes + DeserializeOwned,
{ {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use lib_ot::core::DeltaBuilder; /// use lib_ot::core::OperationBuilder;
/// use lib_ot::rich_text::{RichTextDelta}; /// use lib_ot::text_delta::{TextDelta};
/// let json = r#"[ /// let json = r#"[
/// {"retain":7,"attributes":{"bold":null}} /// {"retain":7,"attributes":{"bold":null}}
/// ]"#; /// ]"#;
/// let delta = RichTextDelta::from_json(json).unwrap(); /// let delta = TextDelta::from_json(json).unwrap();
/// assert_eq!(delta.json_str(), r#"[{"retain":7,"attributes":{"bold":""}}]"#); /// assert_eq!(delta.json_str(), r#"[{"retain":7,"attributes":{"bold":""}}]"#);
/// ``` /// ```
pub fn from_json(json: &str) -> Result<Self, OTError> { pub fn from_json(json: &str) -> Result<Self, OTError> {
@ -595,7 +595,7 @@ where
} }
} }
impl<T> Delta<T> impl<T> Operations<T>
where where
T: Attributes + serde::Serialize, T: Attributes + serde::Serialize,
{ {
@ -616,36 +616,36 @@ where
} }
} }
impl<T> FromStr for Delta<T> impl<T> FromStr for Operations<T>
where where
T: Attributes, T: Attributes,
{ {
type Err = (); type Err = ();
fn from_str(s: &str) -> Result<Delta<T>, Self::Err> { fn from_str(s: &str) -> Result<Operations<T>, Self::Err> {
let mut delta = Delta::with_capacity(1); let mut delta = Operations::with_capacity(1);
delta.add(Operation::Insert(s.into())); delta.add(Operation::Insert(s.into()));
Ok(delta) Ok(delta)
} }
} }
impl<T> std::convert::TryFrom<Vec<u8>> for Delta<T> impl<T> std::convert::TryFrom<Vec<u8>> for Operations<T>
where where
T: Attributes + DeserializeOwned, T: Attributes + DeserializeOwned,
{ {
type Error = OTError; type Error = OTError;
fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> { fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> {
Delta::from_bytes(bytes) Operations::from_bytes(bytes)
} }
} }
impl<T> std::convert::TryFrom<Bytes> for Delta<T> impl<T> std::convert::TryFrom<Bytes> for Operations<T>
where where
T: Attributes + DeserializeOwned, T: Attributes + DeserializeOwned,
{ {
type Error = OTError; type Error = OTError;
fn try_from(bytes: Bytes) -> Result<Self, Self::Error> { fn try_from(bytes: Bytes) -> Result<Self, Self::Error> {
Delta::from_bytes(&bytes) Operations::from_bytes(&bytes)
} }
} }

View File

@ -1,5 +1,5 @@
use crate::core::delta::Delta; use crate::core::delta::operation::Attributes;
use crate::core::operation::Attributes; use crate::core::delta::Operations;
use serde::{ use serde::{
de::{SeqAccess, Visitor}, de::{SeqAccess, Visitor},
ser::SerializeSeq, ser::SerializeSeq,
@ -7,7 +7,7 @@ use serde::{
}; };
use std::{fmt, marker::PhantomData}; use std::{fmt, marker::PhantomData};
impl<T> Serialize for Delta<T> impl<T> Serialize for Operations<T>
where where
T: Attributes + Serialize, T: Attributes + Serialize,
{ {
@ -23,11 +23,11 @@ where
} }
} }
impl<'de, T> Deserialize<'de> for Delta<T> impl<'de, T> Deserialize<'de> for Operations<T>
where where
T: Attributes + Deserialize<'de>, T: Attributes + Deserialize<'de>,
{ {
fn deserialize<D>(deserializer: D) -> Result<Delta<T>, D::Error> fn deserialize<D>(deserializer: D) -> Result<Operations<T>, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
@ -37,7 +37,7 @@ where
where where
T: Attributes + Deserialize<'de>, T: Attributes + Deserialize<'de>,
{ {
type Value = Delta<T>; type Value = Operations<T>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a sequence") formatter.write_str("a sequence")
@ -48,7 +48,7 @@ where
where where
A: SeqAccess<'de>, A: SeqAccess<'de>,
{ {
let mut o = Delta::default(); let mut o = Operations::default();
while let Some(op) = seq.next_element()? { while let Some(op) = seq.next_element()? {
o.add(op); o.add(op);
} }

View File

@ -2,7 +2,7 @@ use super::node_serde::*;
use crate::core::NodeBody::Delta; use crate::core::NodeBody::Delta;
use crate::core::{AttributeKey, AttributeValue, NodeAttributes, OperationTransform}; use crate::core::{AttributeKey, AttributeValue, NodeAttributes, OperationTransform};
use crate::errors::OTError; use crate::errors::OTError;
use crate::rich_text::RichTextDelta; use crate::text_delta::TextDelta;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Default, Clone, Serialize, Deserialize, Eq, PartialEq)] #[derive(Default, Clone, Serialize, Deserialize, Eq, PartialEq)]
@ -93,7 +93,7 @@ impl NodeDataBuilder {
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum NodeBody { pub enum NodeBody {
Empty, Empty,
Delta(RichTextDelta), Delta(TextDelta),
} }
impl std::default::Default for NodeBody { impl std::default::Default for NodeBody {
@ -161,10 +161,7 @@ impl OperationTransform for NodeBody {
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
pub enum NodeBodyChangeset { pub enum NodeBodyChangeset {
Delta { Delta { delta: TextDelta, inverted: TextDelta },
delta: RichTextDelta,
inverted: RichTextDelta,
},
} }
impl NodeBodyChangeset { impl NodeBodyChangeset {

View File

@ -1,5 +1,5 @@
use super::NodeBody; use super::NodeBody;
use crate::rich_text::RichTextDelta; use crate::text_delta::TextDelta;
use serde::de::{self, MapAccess, Visitor}; use serde::de::{self, MapAccess, Visitor};
use serde::ser::SerializeMap; use serde::ser::SerializeMap;
use serde::{Deserializer, Serializer}; use serde::{Deserializer, Serializer};
@ -37,7 +37,7 @@ where
where where
A: de::SeqAccess<'de>, A: de::SeqAccess<'de>,
{ {
let mut delta = RichTextDelta::default(); let mut delta = TextDelta::default();
while let Some(op) = seq.next_element()? { while let Some(op) = seq.next_element()? {
delta.add(op); delta.add(op);
} }
@ -49,7 +49,7 @@ where
where where
V: MapAccess<'de>, V: MapAccess<'de>,
{ {
let mut delta: Option<RichTextDelta> = None; let mut delta: Option<TextDelta> = None;
while let Some(key) = map.next_key()? { while let Some(key) = map.next_key()? {
match key { match key {
"delta" => { "delta" => {

View File

@ -1,5 +1,5 @@
use crate::core::{NodeBodyChangeset, Path}; use crate::core::{NodeBodyChangeset, Path};
use crate::rich_text::RichTextDelta; use crate::text_delta::TextDelta;
use serde::de::{self, MapAccess, Visitor}; use serde::de::{self, MapAccess, Visitor};
use serde::ser::SerializeMap; use serde::ser::SerializeMap;
use serde::{Deserializer, Serializer}; use serde::{Deserializer, Serializer};
@ -88,8 +88,8 @@ where
#[allow(dead_code)] #[allow(dead_code)]
struct DeltaBodyChangeset<E> { struct DeltaBodyChangeset<E> {
delta: Option<RichTextDelta>, delta: Option<TextDelta>,
inverted: Option<RichTextDelta>, inverted: Option<TextDelta>,
error: PhantomData<E>, error: PhantomData<E>,
} }

View File

@ -1,11 +1,10 @@
mod delta; mod delta;
mod document; mod document;
mod interval; mod interval;
mod operation;
mod ot_str; mod ot_str;
pub use delta::operation::*;
pub use delta::*; pub use delta::*;
pub use document::*; pub use document::*;
pub use interval::*; pub use interval::*;
pub use operation::*;
pub use ot_str::*; pub use ot_str::*;

View File

@ -1,4 +1,4 @@
pub mod codec; pub mod codec;
pub mod core; pub mod core;
pub mod errors; pub mod errors;
pub mod rich_text; pub mod text_delta;

View File

@ -1,5 +0,0 @@
use crate::core::{Delta, DeltaBuilder};
use crate::rich_text::TextAttributes;
pub type RichTextDelta = Delta<TextAttributes>;
pub type RichTextDeltaBuilder = DeltaBuilder<TextAttributes>;

View File

@ -1,11 +0,0 @@
mod attributes;
mod attributes_serde;
mod builder;
#[macro_use]
mod macros;
mod delta;
pub use attributes::*;
pub use builder::*;
pub use delta::*;

View File

@ -1,6 +1,6 @@
#![allow(non_snake_case)] #![allow(non_snake_case)]
#![allow(clippy::derivable_impls)] #![allow(clippy::derivable_impls)]
use crate::rich_text::{TextAttribute, TextAttributes}; use crate::text_delta::{TextAttribute, TextAttributes};
pub struct AttributeBuilder { pub struct AttributeBuilder {
inner: TextAttributes, inner: TextAttributes,

View File

@ -1,5 +1,5 @@
#[rustfmt::skip] #[rustfmt::skip]
use crate::rich_text::{TextAttribute, TextAttributeKey, TextAttributes, TextAttributeValue}; use crate::text_delta::{TextAttribute, TextAttributeKey, TextAttributes, TextAttributeValue};
use serde::{ use serde::{
de, de,
de::{MapAccess, Visitor}, de::{MapAccess, Visitor},

View File

@ -0,0 +1,11 @@
mod attribute_builder;
mod attributes;
mod attributes_serde;
#[macro_use]
mod macros;
mod text_delta;
pub use attribute_builder::*;
pub use attributes::*;
pub use text_delta::*;

View File

@ -0,0 +1,5 @@
use crate::core::{OperationBuilder, Operations};
use crate::text_delta::TextAttributes;
pub type TextDelta = Operations<TextAttributes>;
pub type TextDeltaBuilder = OperationBuilder<TextAttributes>;

View File

@ -1,16 +1,16 @@
use super::script::{NodeScript::*, *}; use super::script::{NodeScript::*, *};
use lib_ot::{ use lib_ot::{
core::{NodeData, Path}, core::{NodeData, Path},
rich_text::{AttributeBuilder, RichTextDeltaBuilder, TextAttribute, TextAttributes}, text_delta::{AttributeBuilder, TextAttribute, TextAttributes, TextDeltaBuilder},
}; };
#[test] #[test]
fn appflowy_editor_deserialize_node_test() { fn editor_deserialize_node_test() {
let mut test = NodeTest::new(); let mut test = NodeTest::new();
let node: NodeData = serde_json::from_str(EXAMPLE_JSON).unwrap(); let node: NodeData = serde_json::from_str(EXAMPLE_JSON).unwrap();
let path: Path = 0.into(); let path: Path = 0.into();
let expected_delta = RichTextDeltaBuilder::new() let expected_delta = TextDeltaBuilder::new()
.insert("👋 ") .insert("👋 ")
.insert_with_attributes( .insert_with_attributes(
"Welcome to ", "Welcome to ",

View File

@ -1,6 +1,6 @@
use lib_ot::{ use lib_ot::{
core::{NodeAttributeBuilder, NodeBodyChangeset, NodeData, NodeDataBuilder, NodeOperation, Path}, core::{NodeAttributeBuilder, NodeBodyChangeset, NodeData, NodeDataBuilder, NodeOperation, Path},
rich_text::RichTextDeltaBuilder, text_delta::TextDeltaBuilder,
}; };
#[test] #[test]
@ -46,7 +46,7 @@ fn operation_update_node_attributes_serde_test() {
#[test] #[test]
fn operation_update_node_body_serialize_test() { fn operation_update_node_body_serialize_test() {
let delta = RichTextDeltaBuilder::new().insert("AppFlowy...").build(); let delta = TextDeltaBuilder::new().insert("AppFlowy...").build();
let inverted = delta.invert_str(""); let inverted = delta.invert_str("");
let changeset = NodeBodyChangeset::Delta { delta, inverted }; let changeset = NodeBodyChangeset::Delta { delta, inverted };
let insert = NodeOperation::UpdateBody { let insert = NodeOperation::UpdateBody {

View File

@ -1,6 +1,6 @@
use lib_ot::{ use lib_ot::{
core::{NodeAttributes, NodeBody, NodeBodyChangeset, NodeData, NodeTree, Path, TransactionBuilder}, core::{NodeAttributes, NodeBody, NodeBodyChangeset, NodeData, NodeTree, Path, TransactionBuilder},
rich_text::RichTextDelta, text_delta::TextDelta,
}; };
pub enum NodeScript { pub enum NodeScript {
@ -10,7 +10,7 @@ pub enum NodeScript {
DeleteNode { path: Path }, DeleteNode { path: Path },
AssertNumberOfNodesAtPath { path: Option<Path>, len: usize }, AssertNumberOfNodesAtPath { path: Option<Path>, len: usize },
AssertNode { path: Path, expected: Option<NodeData> }, AssertNode { path: Path, expected: Option<NodeData> },
AssertNodeDelta { path: Path, expected: RichTextDelta }, AssertNodeDelta { path: Path, expected: TextDelta },
} }
pub struct NodeTest { pub struct NodeTest {

View File

@ -4,7 +4,7 @@ use lib_ot::core::NodeBody;
use lib_ot::core::NodeBodyChangeset; use lib_ot::core::NodeBodyChangeset;
use lib_ot::core::OperationTransform; use lib_ot::core::OperationTransform;
use lib_ot::core::{NodeData, NodeDataBuilder, Path}; use lib_ot::core::{NodeData, NodeDataBuilder, Path};
use lib_ot::rich_text::RichTextDeltaBuilder; use lib_ot::text_delta::TextDeltaBuilder;
#[test] #[test]
fn node_insert_test() { fn node_insert_test() {
@ -186,8 +186,8 @@ fn node_update_body_test() {
let path: Path = 0.into(); let path: Path = 0.into();
let s = "Hello".to_owned(); let s = "Hello".to_owned();
let init_delta = RichTextDeltaBuilder::new().insert(&s).build(); let init_delta = TextDeltaBuilder::new().insert(&s).build();
let delta = RichTextDeltaBuilder::new().retain(s.len()).insert(" AppFlowy").build(); let delta = TextDeltaBuilder::new().retain(s.len()).insert(" AppFlowy").build();
let inverted = delta.invert(&init_delta); let inverted = delta.invert(&init_delta);
let expected = init_delta.compose(&delta).unwrap(); let expected = init_delta.compose(&delta).unwrap();