diff --git a/frontend/rust-lib/flowy-revision/src/conflict_resolve.rs b/frontend/rust-lib/flowy-revision/src/conflict_resolve.rs index 8b36d554cd..afb8379631 100644 --- a/frontend/rust-lib/flowy-revision/src/conflict_resolve.rs +++ b/frontend/rust-lib/flowy-revision/src/conflict_resolve.rs @@ -10,7 +10,7 @@ use flowy_sync::{ }; use lib_infra::future::BoxResultFuture; use lib_ot::core::{Attributes, Delta, PhantomAttributes}; -use lib_ot::rich_text::RichTextAttributes; +use lib_ot::rich_text::TextAttributes; use serde::de::DeserializeOwned; use std::{convert::TryFrom, sync::Arc}; @@ -30,7 +30,7 @@ pub trait ConflictRevisionSink: Send + Sync + 'static { fn ack(&self, rev_id: String, ty: ServerRevisionWSDataType) -> BoxResultFuture<(), FlowyError>; } -pub type RichTextConflictController = ConflictController; +pub type RichTextConflictController = ConflictController; pub type PlainTextConflictController = ConflictController; pub struct ConflictController @@ -175,7 +175,7 @@ where } } -pub type RichTextTransformDeltas = TransformDeltas; +pub type RichTextTransformDeltas = TransformDeltas; pub struct TransformDeltas where diff --git a/frontend/rust-lib/flowy-text-block/src/editor.rs b/frontend/rust-lib/flowy-text-block/src/editor.rs index 2649b2bae1..ccbfe3d694 100644 --- a/frontend/rust-lib/flowy-text-block/src/editor.rs +++ b/frontend/rust-lib/flowy-text-block/src/editor.rs @@ -15,7 +15,7 @@ use flowy_sync::{ }; use lib_ot::{ core::{Interval, Operation}, - rich_text::{RichTextAttribute, RichTextDelta}, + rich_text::{RichTextDelta, TextAttribute}, }; use lib_ws::WSConnectState; use std::sync::Arc; @@ -85,7 +85,7 @@ impl TextBlockEditor { Ok(()) } - pub async fn format(&self, interval: Interval, attribute: RichTextAttribute) -> Result<(), FlowyError> { + pub async fn format(&self, interval: Interval, attribute: TextAttribute) -> Result<(), FlowyError> { let (ret, rx) = oneshot::channel::>(); let msg = EditorCommand::Format { interval, diff --git a/frontend/rust-lib/flowy-text-block/src/queue.rs b/frontend/rust-lib/flowy-text-block/src/queue.rs index e48c39fb97..b9a98f1529 100644 --- a/frontend/rust-lib/flowy-text-block/src/queue.rs +++ b/frontend/rust-lib/flowy-text-block/src/queue.rs @@ -13,7 +13,7 @@ use flowy_sync::{ use futures::stream::StreamExt; use lib_ot::{ core::{Interval, OperationTransform}, - rich_text::{RichTextAttribute, RichTextAttributes, RichTextDelta}, + rich_text::{RichTextDelta, TextAttribute, TextAttributes}, }; use std::sync::Arc; use tokio::sync::{oneshot, RwLock}; @@ -194,7 +194,7 @@ impl EditBlockQueue { pub(crate) struct TextBlockRevisionCompactor(); impl RevisionCompactor for TextBlockRevisionCompactor { fn bytes_from_revisions(&self, revisions: Vec) -> FlowyResult { - let delta = make_delta_from_revisions::(revisions)?; + let delta = make_delta_from_revisions::(revisions)?; Ok(delta.json_bytes()) } } @@ -229,7 +229,7 @@ pub(crate) enum EditorCommand { }, Format { interval: Interval, - attribute: RichTextAttribute, + attribute: TextAttribute, ret: Ret<()>, }, Replace { diff --git a/frontend/rust-lib/flowy-text-block/src/web_socket.rs b/frontend/rust-lib/flowy-text-block/src/web_socket.rs index a44214f4f2..e4919b917a 100644 --- a/frontend/rust-lib/flowy-text-block/src/web_socket.rs +++ b/frontend/rust-lib/flowy-text-block/src/web_socket.rs @@ -10,8 +10,8 @@ use flowy_sync::{ errors::CollaborateResult, }; use lib_infra::future::{BoxResultFuture, FutureResult}; -use lib_ot::rich_text::RichTextAttributes; use lib_ot::rich_text::RichTextDelta; +use lib_ot::rich_text::TextAttributes; use lib_ws::WSConnectState; use std::{sync::Arc, time::Duration}; use tokio::sync::{ @@ -111,7 +111,7 @@ struct TextBlockConflictResolver { edit_cmd_tx: EditorCommandSender, } -impl ConflictResolver for TextBlockConflictResolver { +impl ConflictResolver for TextBlockConflictResolver { fn compose_delta(&self, delta: RichTextDelta) -> BoxResultFuture { let tx = self.edit_cmd_tx.clone(); Box::pin(async move { diff --git a/frontend/rust-lib/flowy-text-block/tests/editor/mod.rs b/frontend/rust-lib/flowy-text-block/tests/editor/mod.rs index bbfd1da6f8..8f2921d203 100644 --- a/frontend/rust-lib/flowy-text-block/tests/editor/mod.rs +++ b/frontend/rust-lib/flowy-text-block/tests/editor/mod.rs @@ -8,7 +8,7 @@ use derive_more::Display; use flowy_sync::client_document::{ClientDocument, InitialDocumentText}; use lib_ot::{ core::*, - rich_text::{RichTextAttribute, RichTextAttributes, RichTextDelta}, + rich_text::{RichTextDelta, TextAttribute, TextAttributes}, }; use rand::{prelude::*, Rng as WrappedRng}; use std::{sync::Once, time::Duration}; @@ -127,11 +127,11 @@ impl TestBuilder { TestOp::InsertBold(delta_i, s, iv) => { let document = &mut self.documents[*delta_i]; document.insert(iv.start, s).unwrap(); - document.format(*iv, RichTextAttribute::Bold(true)).unwrap(); + document.format(*iv, TextAttribute::Bold(true)).unwrap(); } TestOp::Bold(delta_i, iv, enable) => { let document = &mut self.documents[*delta_i]; - let attribute = RichTextAttribute::Bold(*enable); + let attribute = TextAttribute::Bold(*enable); let delta = document.format(*iv, attribute).unwrap(); tracing::trace!("Bold delta: {}", delta.json_str()); self.deltas.insert(*delta_i, Some(delta)); @@ -139,8 +139,8 @@ impl TestBuilder { TestOp::Italic(delta_i, iv, enable) => { let document = &mut self.documents[*delta_i]; let attribute = match *enable { - true => RichTextAttribute::Italic(true), - false => RichTextAttribute::Italic(false), + true => TextAttribute::Italic(true), + false => TextAttribute::Italic(false), }; let delta = document.format(*iv, attribute).unwrap(); tracing::trace!("Italic delta: {}", delta.json_str()); @@ -148,21 +148,21 @@ impl TestBuilder { } TestOp::Header(delta_i, iv, level) => { let document = &mut self.documents[*delta_i]; - let attribute = RichTextAttribute::Header(*level); + let attribute = TextAttribute::Header(*level); let delta = document.format(*iv, attribute).unwrap(); tracing::trace!("Header delta: {}", delta.json_str()); self.deltas.insert(*delta_i, Some(delta)); } TestOp::Link(delta_i, iv, link) => { let document = &mut self.documents[*delta_i]; - let attribute = RichTextAttribute::Link(link.to_owned()); + let attribute = TextAttribute::Link(link.to_owned()); let delta = document.format(*iv, attribute).unwrap(); tracing::trace!("Link delta: {}", delta.json_str()); self.deltas.insert(*delta_i, Some(delta)); } TestOp::Bullet(delta_i, iv, enable) => { let document = &mut self.documents[*delta_i]; - let attribute = RichTextAttribute::Bullet(*enable); + let attribute = TextAttribute::Bullet(*enable); let delta = document.format(*iv, attribute).unwrap(); tracing::debug!("Bullet delta: {}", delta.json_str()); @@ -313,18 +313,18 @@ impl Rng { }; match self.0.gen_range(0.0..1.0) { f if f < 0.2 => { - delta.insert(&self.gen_string(i), RichTextAttributes::default()); + delta.insert(&self.gen_string(i), TextAttributes::default()); } f if f < 0.4 => { delta.delete(i); } _ => { - delta.retain(i, RichTextAttributes::default()); + delta.retain(i, TextAttributes::default()); } } } if self.0.gen_range(0.0..1.0) < 0.3 { - delta.insert(&("1".to_owned() + &self.gen_string(10)), RichTextAttributes::default()); + delta.insert(&("1".to_owned() + &self.gen_string(10)), TextAttributes::default()); } delta } diff --git a/frontend/rust-lib/flowy-text-block/tests/editor/op_test.rs b/frontend/rust-lib/flowy-text-block/tests/editor/op_test.rs index 99d3136e55..fd25a2e8f2 100644 --- a/frontend/rust-lib/flowy-text-block/tests/editor/op_test.rs +++ b/frontend/rust-lib/flowy-text-block/tests/editor/op_test.rs @@ -5,7 +5,7 @@ use lib_ot::rich_text::RichTextDeltaBuilder; use lib_ot::{ core::Interval, core::*, - rich_text::{AttributeBuilder, RichTextAttribute, RichTextAttributes, RichTextDelta}, + rich_text::{AttributeBuilder, RichTextDelta, TextAttribute, TextAttributes}, }; #[test] @@ -207,8 +207,8 @@ fn delta_utf16_code_unit_seek() { fn delta_utf16_code_unit_seek_with_attributes() { let mut delta = RichTextDelta::default(); let attributes = AttributeBuilder::new() - .add_attr(RichTextAttribute::Bold(true)) - .add_attr(RichTextAttribute::Italic(true)) + .add_attr(TextAttribute::Bold(true)) + .add_attr(TextAttribute::Italic(true)) .build(); delta.add(Operation::insert_with_attributes("1234", attributes.clone())); @@ -304,13 +304,13 @@ fn lengths() { let mut delta = RichTextDelta::default(); assert_eq!(delta.utf16_base_len, 0); assert_eq!(delta.utf16_target_len, 0); - delta.retain(5, RichTextAttributes::default()); + delta.retain(5, TextAttributes::default()); assert_eq!(delta.utf16_base_len, 5); assert_eq!(delta.utf16_target_len, 5); - delta.insert("abc", RichTextAttributes::default()); + delta.insert("abc", TextAttributes::default()); assert_eq!(delta.utf16_base_len, 5); assert_eq!(delta.utf16_target_len, 8); - delta.retain(2, RichTextAttributes::default()); + delta.retain(2, TextAttributes::default()); assert_eq!(delta.utf16_base_len, 7); assert_eq!(delta.utf16_target_len, 10); delta.delete(2); @@ -320,10 +320,10 @@ fn lengths() { #[test] fn sequence() { let mut delta = RichTextDelta::default(); - delta.retain(5, RichTextAttributes::default()); - delta.retain(0, RichTextAttributes::default()); - delta.insert("appflowy", RichTextAttributes::default()); - delta.insert("", RichTextAttributes::default()); + delta.retain(5, TextAttributes::default()); + delta.retain(0, TextAttributes::default()); + delta.insert("appflowy", TextAttributes::default()); + delta.insert("", TextAttributes::default()); delta.delete(3); delta.delete(0); assert_eq!(delta.ops.len(), 3); @@ -353,15 +353,15 @@ fn apply_test() { #[test] fn base_len_test() { let mut delta_a = RichTextDelta::default(); - delta_a.insert("a", RichTextAttributes::default()); - delta_a.insert("b", RichTextAttributes::default()); - delta_a.insert("c", RichTextAttributes::default()); + delta_a.insert("a", TextAttributes::default()); + delta_a.insert("b", TextAttributes::default()); + delta_a.insert("c", TextAttributes::default()); let s = "hello world,".to_owned(); delta_a.delete(s.len()); let after_a = delta_a.apply(&s).unwrap(); - delta_a.insert("d", RichTextAttributes::default()); + delta_a.insert("d", TextAttributes::default()); assert_eq!("abc", &after_a); } @@ -392,8 +392,8 @@ fn invert_test() { #[test] fn empty_ops() { let mut delta = RichTextDelta::default(); - delta.retain(0, RichTextAttributes::default()); - delta.insert("", RichTextAttributes::default()); + delta.retain(0, TextAttributes::default()); + delta.insert("", TextAttributes::default()); delta.delete(0); assert_eq!(delta.ops.len(), 0); } @@ -401,33 +401,33 @@ fn empty_ops() { fn eq() { let mut delta_a = RichTextDelta::default(); delta_a.delete(1); - delta_a.insert("lo", RichTextAttributes::default()); - delta_a.retain(2, RichTextAttributes::default()); - delta_a.retain(3, RichTextAttributes::default()); + delta_a.insert("lo", TextAttributes::default()); + delta_a.retain(2, TextAttributes::default()); + delta_a.retain(3, TextAttributes::default()); let mut delta_b = RichTextDelta::default(); delta_b.delete(1); - delta_b.insert("l", RichTextAttributes::default()); - delta_b.insert("o", RichTextAttributes::default()); - delta_b.retain(5, RichTextAttributes::default()); + delta_b.insert("l", TextAttributes::default()); + delta_b.insert("o", TextAttributes::default()); + delta_b.retain(5, TextAttributes::default()); assert_eq!(delta_a, delta_b); delta_a.delete(1); - delta_b.retain(1, RichTextAttributes::default()); + delta_b.retain(1, TextAttributes::default()); assert_ne!(delta_a, delta_b); } #[test] fn ops_merging() { let mut delta = RichTextDelta::default(); assert_eq!(delta.ops.len(), 0); - delta.retain(2, RichTextAttributes::default()); + delta.retain(2, TextAttributes::default()); assert_eq!(delta.ops.len(), 1); assert_eq!(delta.ops.last(), Some(&Operation::retain(2))); - delta.retain(3, RichTextAttributes::default()); + delta.retain(3, TextAttributes::default()); assert_eq!(delta.ops.len(), 1); assert_eq!(delta.ops.last(), Some(&Operation::retain(5))); - delta.insert("abc", RichTextAttributes::default()); + delta.insert("abc", TextAttributes::default()); assert_eq!(delta.ops.len(), 2); assert_eq!(delta.ops.last(), Some(&Operation::insert("abc"))); - delta.insert("xyz", RichTextAttributes::default()); + delta.insert("xyz", TextAttributes::default()); assert_eq!(delta.ops.len(), 2); assert_eq!(delta.ops.last(), Some(&Operation::insert("abcxyz"))); delta.delete(1); @@ -442,11 +442,11 @@ fn ops_merging() { fn is_noop() { let mut delta = RichTextDelta::default(); assert!(delta.is_noop()); - delta.retain(5, RichTextAttributes::default()); + delta.retain(5, TextAttributes::default()); assert!(delta.is_noop()); - delta.retain(3, RichTextAttributes::default()); + delta.retain(3, TextAttributes::default()); assert!(delta.is_noop()); - delta.insert("lorem", RichTextAttributes::default()); + delta.insert("lorem", TextAttributes::default()); assert!(!delta.is_noop()); } #[test] @@ -492,14 +492,14 @@ fn transform_with_two_delta() { let mut a_s = String::new(); a.insert( "123", - AttributeBuilder::new().add_attr(RichTextAttribute::Bold(true)).build(), + AttributeBuilder::new().add_attr(TextAttribute::Bold(true)).build(), ); a_s = a.apply(&a_s).unwrap(); assert_eq!(&a_s, "123"); let mut b = RichTextDelta::default(); let mut b_s = String::new(); - b.insert("456", RichTextAttributes::default()); + b.insert("456", TextAttributes::default()); b_s = b.apply(&b_s).unwrap(); assert_eq!(&b_s, "456"); diff --git a/frontend/rust-lib/flowy-text-block/tests/editor/serde_test.rs b/frontend/rust-lib/flowy-text-block/tests/editor/serde_test.rs index ac4a77412c..2d2e6bc143 100644 --- a/frontend/rust-lib/flowy-text-block/tests/editor/serde_test.rs +++ b/frontend/rust-lib/flowy-text-block/tests/editor/serde_test.rs @@ -2,14 +2,14 @@ use flowy_sync::client_document::{ClientDocument, PlainDoc}; use lib_ot::rich_text::RichTextOperation; use lib_ot::{ core::*, - rich_text::{AttributeBuilder, RichTextAttribute, RichTextAttributeValue, RichTextDelta}, + rich_text::{AttributeBuilder, RichTextDelta, TextAttribute, TextAttributeValue}, }; #[test] fn operation_insert_serialize_test() { let attributes = AttributeBuilder::new() - .add_attr(RichTextAttribute::Bold(true)) - .add_attr(RichTextAttribute::Italic(true)) + .add_attr(TextAttribute::Bold(true)) + .add_attr(TextAttribute::Italic(true)) .build(); let operation = Operation::insert_with_attributes("123", attributes); let json = serde_json::to_string(&operation).unwrap(); @@ -39,8 +39,8 @@ fn operation_delete_serialize_test() { #[test] fn attributes_serialize_test() { let attributes = AttributeBuilder::new() - .add_attr(RichTextAttribute::Bold(true)) - .add_attr(RichTextAttribute::Italic(true)) + .add_attr(TextAttribute::Bold(true)) + .add_attr(TextAttribute::Italic(true)) .build(); let retain = Operation::insert_with_attributes("123", attributes); @@ -53,8 +53,8 @@ fn delta_serialize_multi_attribute_test() { let mut delta = Delta::default(); let attributes = AttributeBuilder::new() - .add_attr(RichTextAttribute::Bold(true)) - .add_attr(RichTextAttribute::Italic(true)) + .add_attr(TextAttribute::Bold(true)) + .add_attr(TextAttribute::Italic(true)) .build(); let retain = Operation::insert_with_attributes("123", attributes); @@ -88,8 +88,8 @@ fn delta_deserialize_null_test() { ]"#; let delta1 = RichTextDelta::from_json(json).unwrap(); - let mut attribute = RichTextAttribute::Bold(true); - attribute.value = RichTextAttributeValue(None); + let mut attribute = TextAttribute::Bold(true); + attribute.value = TextAttributeValue(None); let delta2 = DeltaBuilder::new().retain_with_attributes(7, attribute.into()).build(); assert_eq!(delta2.json_str(), r#"[{"retain":7,"attributes":{"bold":""}}]"#); @@ -98,8 +98,8 @@ fn delta_deserialize_null_test() { #[test] fn delta_serde_null_test() { - let mut attribute = RichTextAttribute::Bold(true); - attribute.value = RichTextAttributeValue(None); + let mut attribute = TextAttribute::Bold(true); + attribute.value = TextAttributeValue(None); assert_eq!(attribute.to_json(), r#"{"bold":""}"#); } diff --git a/shared-lib/flowy-sync/src/client_document/document_pad.rs b/shared-lib/flowy-sync/src/client_document/document_pad.rs index 9a1037d0c8..28915e259d 100644 --- a/shared-lib/flowy-sync/src/client_document/document_pad.rs +++ b/shared-lib/flowy-sync/src/client_document/document_pad.rs @@ -9,7 +9,7 @@ use crate::{ use bytes::Bytes; use lib_ot::{ core::*, - rich_text::{RichTextAttribute, RichTextDelta}, + rich_text::{RichTextDelta, TextAttribute}, }; use tokio::sync::mpsc; @@ -141,11 +141,7 @@ impl ClientDocument { Ok(delete) } - pub fn format( - &mut self, - interval: Interval, - attribute: RichTextAttribute, - ) -> Result { + pub fn format(&mut self, interval: Interval, attribute: TextAttribute) -> Result { let _ = validate_interval(&self.delta, &interval)?; tracing::trace!("format {} with {}", interval, attribute); let format_delta = self.view.format(&self.delta, attribute, interval).unwrap(); diff --git a/shared-lib/flowy-sync/src/client_document/extensions/format/resolve_block_format.rs b/shared-lib/flowy-sync/src/client_document/extensions/format/resolve_block_format.rs index 4a4c00a19d..3437080f37 100644 --- a/shared-lib/flowy-sync/src/client_document/extensions/format/resolve_block_format.rs +++ b/shared-lib/flowy-sync/src/client_document/extensions/format/resolve_block_format.rs @@ -1,6 +1,6 @@ use lib_ot::{ core::{DeltaBuilder, DeltaIterator, Interval}, - rich_text::{plain_attributes, AttributeScope, RichTextAttribute, RichTextDelta}, + rich_text::{plain_attributes, AttributeScope, RichTextDelta, TextAttribute}, }; use crate::{ @@ -14,7 +14,7 @@ impl FormatExt for ResolveBlockFormat { "ResolveBlockFormat" } - fn apply(&self, delta: &RichTextDelta, interval: Interval, attribute: &RichTextAttribute) -> Option { + fn apply(&self, delta: &RichTextDelta, interval: Interval, attribute: &TextAttribute) -> Option { if attribute.scope != AttributeScope::Block { return None; } diff --git a/shared-lib/flowy-sync/src/client_document/extensions/format/resolve_inline_format.rs b/shared-lib/flowy-sync/src/client_document/extensions/format/resolve_inline_format.rs index 567d06d6f2..8b654b0787 100644 --- a/shared-lib/flowy-sync/src/client_document/extensions/format/resolve_inline_format.rs +++ b/shared-lib/flowy-sync/src/client_document/extensions/format/resolve_inline_format.rs @@ -1,6 +1,6 @@ use lib_ot::{ core::{DeltaBuilder, DeltaIterator, Interval}, - rich_text::{AttributeScope, RichTextAttribute, RichTextDelta}, + rich_text::{AttributeScope, RichTextDelta, TextAttribute}, }; use crate::{ @@ -14,7 +14,7 @@ impl FormatExt for ResolveInlineFormat { "ResolveInlineFormat" } - fn apply(&self, delta: &RichTextDelta, interval: Interval, attribute: &RichTextAttribute) -> Option { + fn apply(&self, delta: &RichTextDelta, interval: Interval, attribute: &TextAttribute) -> Option { if attribute.scope != AttributeScope::Inline { return None; } diff --git a/shared-lib/flowy-sync/src/client_document/extensions/helper.rs b/shared-lib/flowy-sync/src/client_document/extensions/helper.rs index a4745bf7ca..6c6a0e2d25 100644 --- a/shared-lib/flowy-sync/src/client_document/extensions/helper.rs +++ b/shared-lib/flowy-sync/src/client_document/extensions/helper.rs @@ -1,11 +1,7 @@ use crate::util::find_newline; -use lib_ot::rich_text::{plain_attributes, AttributeScope, RichTextAttribute, RichTextDelta, RichTextOperation}; +use lib_ot::rich_text::{plain_attributes, AttributeScope, RichTextDelta, RichTextOperation, TextAttribute}; -pub(crate) fn line_break( - op: &RichTextOperation, - attribute: &RichTextAttribute, - scope: AttributeScope, -) -> RichTextDelta { +pub(crate) fn line_break(op: &RichTextOperation, attribute: &TextAttribute, scope: AttributeScope) -> RichTextDelta { let mut new_delta = RichTextDelta::new(); let mut start = 0; let end = op.len(); diff --git a/shared-lib/flowy-sync/src/client_document/extensions/insert/auto_exit_block.rs b/shared-lib/flowy-sync/src/client_document/extensions/insert/auto_exit_block.rs index 253833d255..d7a0b7dea5 100644 --- a/shared-lib/flowy-sync/src/client_document/extensions/insert/auto_exit_block.rs +++ b/shared-lib/flowy-sync/src/client_document/extensions/insert/auto_exit_block.rs @@ -1,6 +1,6 @@ use crate::{client_document::InsertExt, util::is_newline}; use lib_ot::core::{is_empty_line_at_index, DeltaBuilder, DeltaIterator}; -use lib_ot::rich_text::{attributes_except_header, RichTextAttributeKey, RichTextDelta}; +use lib_ot::rich_text::{attributes_except_header, RichTextDelta, TextAttributeKey}; pub struct AutoExitBlock {} @@ -42,7 +42,7 @@ impl InsertExt for AutoExitBlock { } } - attributes.mark_all_as_removed_except(Some(RichTextAttributeKey::Header)); + attributes.mark_all_as_removed_except(Some(TextAttributeKey::Header)); Some( DeltaBuilder::new() diff --git a/shared-lib/flowy-sync/src/client_document/extensions/insert/auto_format.rs b/shared-lib/flowy-sync/src/client_document/extensions/insert/auto_format.rs index 4c7cd642c2..07e9d3d116 100644 --- a/shared-lib/flowy-sync/src/client_document/extensions/insert/auto_format.rs +++ b/shared-lib/flowy-sync/src/client_document/extensions/insert/auto_format.rs @@ -1,7 +1,7 @@ use crate::{client_document::InsertExt, util::is_whitespace}; use lib_ot::{ core::{count_utf16_code_units, DeltaBuilder, DeltaIterator}, - rich_text::{plain_attributes, RichTextAttribute, RichTextAttributes, RichTextDelta}, + rich_text::{plain_attributes, RichTextDelta, TextAttribute, TextAttributes}, }; use std::cmp::min; use url::Url; @@ -60,9 +60,9 @@ pub enum AutoFormatter { } impl AutoFormatter { - pub fn to_attributes(&self) -> RichTextAttributes { + pub fn to_attributes(&self) -> TextAttributes { match self { - AutoFormatter::Url(url) => RichTextAttribute::Link(url.as_str()).into(), + AutoFormatter::Url(url) => TextAttribute::Link(url.as_str()).into(), } } diff --git a/shared-lib/flowy-sync/src/client_document/extensions/insert/default_insert.rs b/shared-lib/flowy-sync/src/client_document/extensions/insert/default_insert.rs index c165985493..3f29404136 100644 --- a/shared-lib/flowy-sync/src/client_document/extensions/insert/default_insert.rs +++ b/shared-lib/flowy-sync/src/client_document/extensions/insert/default_insert.rs @@ -1,7 +1,7 @@ use crate::client_document::InsertExt; use lib_ot::{ core::{Attributes, DeltaBuilder, DeltaIterator, NEW_LINE}, - rich_text::{RichTextAttributeKey, RichTextAttributes, RichTextDelta}, + rich_text::{RichTextDelta, TextAttributeKey, TextAttributes}, }; pub struct DefaultInsertAttribute {} @@ -12,7 +12,7 @@ impl InsertExt for DefaultInsertAttribute { fn apply(&self, delta: &RichTextDelta, replace_len: usize, text: &str, index: usize) -> Option { let iter = DeltaIterator::new(delta); - let mut attributes = RichTextAttributes::new(); + let mut attributes = TextAttributes::new(); // Enable each line split by "\n" remains the block attributes. for example: // insert "\n" to "123456" at index 3 @@ -23,7 +23,7 @@ impl InsertExt for DefaultInsertAttribute { match iter.last() { None => {} Some(op) => { - if op.get_attributes().contains_key(&RichTextAttributeKey::Header) { + if op.get_attributes().contains_key(&TextAttributeKey::Header) { attributes.extend_other(op.get_attributes()); } } diff --git a/shared-lib/flowy-sync/src/client_document/extensions/insert/preserve_block_format.rs b/shared-lib/flowy-sync/src/client_document/extensions/insert/preserve_block_format.rs index 03c9723d7b..21c781524f 100644 --- a/shared-lib/flowy-sync/src/client_document/extensions/insert/preserve_block_format.rs +++ b/shared-lib/flowy-sync/src/client_document/extensions/insert/preserve_block_format.rs @@ -2,8 +2,7 @@ use crate::{client_document::InsertExt, util::is_newline}; use lib_ot::{ core::{DeltaBuilder, DeltaIterator, NEW_LINE}, rich_text::{ - attributes_except_header, plain_attributes, RichTextAttribute, RichTextAttributeKey, RichTextAttributes, - RichTextDelta, + attributes_except_header, plain_attributes, RichTextDelta, TextAttribute, TextAttributeKey, TextAttributes, }, }; @@ -28,9 +27,9 @@ impl InsertExt for PreserveBlockFormatOnInsert { return None; } - let mut reset_attribute = RichTextAttributes::new(); - if newline_attributes.contains_key(&RichTextAttributeKey::Header) { - reset_attribute.add(RichTextAttribute::Header(1)); + let mut reset_attribute = TextAttributes::new(); + if newline_attributes.contains_key(&TextAttributeKey::Header) { + reset_attribute.add(TextAttribute::Header(1)); } let lines: Vec<_> = text.split(NEW_LINE).collect(); diff --git a/shared-lib/flowy-sync/src/client_document/extensions/insert/preserve_inline_format.rs b/shared-lib/flowy-sync/src/client_document/extensions/insert/preserve_inline_format.rs index b0de6451aa..be65a1432d 100644 --- a/shared-lib/flowy-sync/src/client_document/extensions/insert/preserve_inline_format.rs +++ b/shared-lib/flowy-sync/src/client_document/extensions/insert/preserve_inline_format.rs @@ -4,7 +4,7 @@ use crate::{ }; use lib_ot::{ core::{DeltaBuilder, DeltaIterator, OpNewline, NEW_LINE}, - rich_text::{plain_attributes, RichTextAttributeKey, RichTextDelta}, + rich_text::{plain_attributes, RichTextDelta, TextAttributeKey}, }; pub struct PreserveInlineFormat {} @@ -25,7 +25,7 @@ impl InsertExt for PreserveInlineFormat { } let mut attributes = prev.get_attributes(); - if attributes.is_empty() || !attributes.contains_key(&RichTextAttributeKey::Link) { + if attributes.is_empty() || !attributes.contains_key(&TextAttributeKey::Link) { return Some( DeltaBuilder::new() .retain(index + replace_len) diff --git a/shared-lib/flowy-sync/src/client_document/extensions/insert/reset_format_on_new_line.rs b/shared-lib/flowy-sync/src/client_document/extensions/insert/reset_format_on_new_line.rs index 8671049ee7..3324df3398 100644 --- a/shared-lib/flowy-sync/src/client_document/extensions/insert/reset_format_on_new_line.rs +++ b/shared-lib/flowy-sync/src/client_document/extensions/insert/reset_format_on_new_line.rs @@ -1,7 +1,7 @@ use crate::{client_document::InsertExt, util::is_newline}; use lib_ot::{ core::{DeltaBuilder, DeltaIterator, Utf16CodeUnitMetric, NEW_LINE}, - rich_text::{RichTextAttributeKey, RichTextAttributes, RichTextDelta}, + rich_text::{RichTextDelta, TextAttributeKey, TextAttributes}, }; pub struct ResetLineFormatOnNewLine {} @@ -22,9 +22,9 @@ impl InsertExt for ResetLineFormatOnNewLine { return None; } - let mut reset_attribute = RichTextAttributes::new(); - if next_op.get_attributes().contains_key(&RichTextAttributeKey::Header) { - reset_attribute.delete(&RichTextAttributeKey::Header); + let mut reset_attribute = TextAttributes::new(); + if next_op.get_attributes().contains_key(&TextAttributeKey::Header) { + reset_attribute.delete(&TextAttributeKey::Header); } let len = index + replace_len; diff --git a/shared-lib/flowy-sync/src/client_document/extensions/mod.rs b/shared-lib/flowy-sync/src/client_document/extensions/mod.rs index d24e78fab1..ffbb6c0a9e 100644 --- a/shared-lib/flowy-sync/src/client_document/extensions/mod.rs +++ b/shared-lib/flowy-sync/src/client_document/extensions/mod.rs @@ -3,7 +3,7 @@ pub use format::*; pub use insert::*; use lib_ot::{ core::Interval, - rich_text::{RichTextAttribute, RichTextDelta}, + rich_text::{RichTextDelta, TextAttribute}, }; mod delete; @@ -22,7 +22,7 @@ pub trait InsertExt { pub trait FormatExt { fn ext_name(&self) -> &str; - fn apply(&self, delta: &RichTextDelta, interval: Interval, attribute: &RichTextAttribute) -> Option; + fn apply(&self, delta: &RichTextDelta, interval: Interval, attribute: &TextAttribute) -> Option; } pub trait DeleteExt { diff --git a/shared-lib/flowy-sync/src/client_document/view.rs b/shared-lib/flowy-sync/src/client_document/view.rs index 3aefe8debd..90b33b0312 100644 --- a/shared-lib/flowy-sync/src/client_document/view.rs +++ b/shared-lib/flowy-sync/src/client_document/view.rs @@ -2,7 +2,7 @@ use crate::client_document::*; use lib_ot::{ core::{trim, Interval}, errors::{ErrorBuilder, OTError, OTErrorCode}, - rich_text::{RichTextAttribute, RichTextDelta}, + rich_text::{RichTextDelta, TextAttribute}, }; pub const RECORD_THRESHOLD: usize = 400; // in milliseconds @@ -64,7 +64,7 @@ impl ViewExtensions { pub(crate) fn format( &self, delta: &RichTextDelta, - attribute: RichTextAttribute, + attribute: TextAttribute, interval: Interval, ) -> Result { let mut new_delta = None; diff --git a/shared-lib/flowy-sync/src/server_document/document_manager.rs b/shared-lib/flowy-sync/src/server_document/document_manager.rs index 59d3dd3c97..a7188799f9 100644 --- a/shared-lib/flowy-sync/src/server_document/document_manager.rs +++ b/shared-lib/flowy-sync/src/server_document/document_manager.rs @@ -11,7 +11,7 @@ use async_stream::stream; use dashmap::DashMap; use futures::stream::StreamExt; use lib_infra::future::BoxResultFuture; -use lib_ot::rich_text::{RichTextAttributes, RichTextDelta}; +use lib_ot::rich_text::{RichTextDelta, TextAttributes}; use std::{collections::HashMap, fmt::Debug, sync::Arc}; use tokio::{ sync::{mpsc, oneshot, RwLock}, @@ -198,7 +198,7 @@ impl std::ops::Drop for ServerDocumentManager { } } -type DocumentRevisionSynchronizer = RevisionSynchronizer; +type DocumentRevisionSynchronizer = RevisionSynchronizer; struct OpenDocumentHandler { doc_id: String, diff --git a/shared-lib/flowy-sync/src/server_document/document_pad.rs b/shared-lib/flowy-sync/src/server_document/document_pad.rs index 28623a0169..f444816cd6 100644 --- a/shared-lib/flowy-sync/src/server_document/document_pad.rs +++ b/shared-lib/flowy-sync/src/server_document/document_pad.rs @@ -1,7 +1,7 @@ use crate::{client_document::InitialDocumentText, errors::CollaborateError, synchronizer::RevisionSyncObject}; use lib_ot::{ core::*, - rich_text::{RichTextAttributes, RichTextDelta}, + rich_text::{RichTextDelta, TextAttributes}, }; pub struct ServerDocument { @@ -21,7 +21,7 @@ impl ServerDocument { } } -impl RevisionSyncObject for ServerDocument { +impl RevisionSyncObject for ServerDocument { fn id(&self) -> &str { &self.doc_id } @@ -42,7 +42,7 @@ impl RevisionSyncObject for ServerDocument { self.delta.json_str() } - fn set_delta(&mut self, new_delta: Delta) { + fn set_delta(&mut self, new_delta: Delta) { self.delta = new_delta; } } diff --git a/shared-lib/lib-ot/src/codec/markdown/markdown_encoder.rs b/shared-lib/lib-ot/src/codec/markdown/markdown_encoder.rs index f338a029a4..82332792e5 100644 --- a/shared-lib/lib-ot/src/codec/markdown/markdown_encoder.rs +++ b/shared-lib/lib-ot/src/codec/markdown/markdown_encoder.rs @@ -1,5 +1,5 @@ use crate::core::{Delta, DeltaIterator}; -use crate::rich_text::{is_block, RichTextAttributeKey, RichTextAttributeValue, RichTextAttributes}; +use crate::rich_text::{is_block, TextAttributeKey, TextAttributeValue, TextAttributes}; use std::collections::HashMap; const LINEFEEDASCIICODE: i32 = 0x0A; @@ -98,14 +98,14 @@ mod tests { } struct Attribute { - key: RichTextAttributeKey, - value: RichTextAttributeValue, + key: TextAttributeKey, + value: TextAttributeValue, } -pub fn markdown_encoder(delta: &Delta) -> String { +pub fn markdown_encoder(delta: &Delta) -> String { let mut markdown_buffer = String::new(); let mut line_buffer = String::new(); - let mut current_inline_style = RichTextAttributes::default(); + let mut current_inline_style = TextAttributes::default(); let mut current_block_lines: Vec = Vec::new(); let mut iterator = DeltaIterator::new(delta); let mut current_block_style: Option = None; @@ -138,17 +138,17 @@ pub fn markdown_encoder(delta: &Delta) -> String { } fn handle_inline( - current_inline_style: &mut RichTextAttributes, + current_inline_style: &mut TextAttributes, buffer: &mut String, mut text: String, - attributes: RichTextAttributes, + attributes: TextAttributes, ) { - let mut marked_for_removal: HashMap = HashMap::new(); + let mut marked_for_removal: HashMap = HashMap::new(); for key in current_inline_style .clone() .keys() - .collect::>() + .collect::>() .into_iter() .rev() { @@ -205,46 +205,46 @@ fn trim_right(buffer: &mut String) -> String { " ".repeat(text.len() - result.len()) } -fn write_attribute(buffer: &mut String, key: &RichTextAttributeKey, value: &RichTextAttributeValue, close: bool) { +fn write_attribute(buffer: &mut String, key: &TextAttributeKey, value: &TextAttributeValue, close: bool) { match key { - RichTextAttributeKey::Bold => buffer.push_str("**"), - RichTextAttributeKey::Italic => buffer.push_str("_"), - RichTextAttributeKey::Underline => { + TextAttributeKey::Bold => buffer.push_str("**"), + TextAttributeKey::Italic => buffer.push_str("_"), + TextAttributeKey::Underline => { if close { buffer.push_str("") } else { buffer.push_str("") } } - RichTextAttributeKey::StrikeThrough => { + TextAttributeKey::StrikeThrough => { if close { buffer.push_str("~~") } else { buffer.push_str("~~") } } - RichTextAttributeKey::Link => { + TextAttributeKey::Link => { if close { buffer.push_str(format!("]({})", value.0.as_ref().unwrap()).as_str()) } else { buffer.push_str("[") } } - RichTextAttributeKey::Background => { + TextAttributeKey::Background => { if close { buffer.push_str("") } else { buffer.push_str("") } } - RichTextAttributeKey::CodeBlock => { + TextAttributeKey::CodeBlock => { if close { buffer.push_str("\n```") } else { buffer.push_str("```\n") } } - RichTextAttributeKey::InlineCode => { + TextAttributeKey::InlineCode => { if close { buffer.push_str("`") } else { @@ -259,10 +259,10 @@ fn handle_line( buffer: &mut String, markdown_buffer: &mut String, data: String, - attributes: RichTextAttributes, + attributes: TextAttributes, current_block_style: &mut Option, current_block_lines: &mut Vec, - current_inline_style: &mut RichTextAttributes, + current_inline_style: &mut TextAttributes, ) { let mut span = String::new(); for c in data.chars() { @@ -274,7 +274,7 @@ fn handle_line( current_inline_style, buffer, String::from(""), - RichTextAttributes::default(), + TextAttributes::default(), ); let line_block_key = attributes.keys().find(|key| { @@ -339,7 +339,7 @@ fn handle_block( markdown_buffer.push_str(¤t_block_lines.join("\n")); markdown_buffer.push('\n'); } - Some(block_style) if block_style.key == RichTextAttributeKey::CodeBlock => { + Some(block_style) if block_style.key == TextAttributeKey::CodeBlock => { write_attribute(markdown_buffer, &block_style.key, &block_style.value, false); markdown_buffer.push_str(¤t_block_lines.join("\n")); write_attribute(markdown_buffer, &block_style.key, &block_style.value, true); @@ -360,9 +360,9 @@ fn write_block_tag(buffer: &mut String, block: &Attribute, close: bool) { return; } - if block.key == RichTextAttributeKey::BlockQuote { + if block.key == TextAttributeKey::BlockQuote { buffer.push_str("> "); - } else if block.key == RichTextAttributeKey::List { + } else if block.key == TextAttributeKey::List { if block.value.0.as_ref().unwrap().eq("bullet") { buffer.push_str("* "); } else if block.value.0.as_ref().unwrap().eq("checked") { @@ -374,14 +374,14 @@ fn write_block_tag(buffer: &mut String, block: &Attribute, close: bool) { } else { buffer.push_str("* "); } - } else if block.key == RichTextAttributeKey::Header { + } else if block.key == TextAttributeKey::Header { if block.value.0.as_ref().unwrap().eq("1") { buffer.push_str("# "); } else if block.value.0.as_ref().unwrap().eq("2") { buffer.push_str("## "); } else if block.value.0.as_ref().unwrap().eq("3") { buffer.push_str("### "); - } else if block.key == RichTextAttributeKey::List { + } else if block.key == TextAttributeKey::List { } } } diff --git a/shared-lib/lib-ot/src/core/delta/builder.rs b/shared-lib/lib-ot/src/core/delta/builder.rs index 482b1ca8a9..d8bede927f 100644 --- a/shared-lib/lib-ot/src/core/delta/builder.rs +++ b/shared-lib/lib-ot/src/core/delta/builder.rs @@ -50,9 +50,9 @@ where /// # Examples /// /// ``` - /// use lib_ot::rich_text::{RichTextAttribute, RichTextDelta, RichTextDeltaBuilder}; + /// use lib_ot::rich_text::{TextAttribute, RichTextDelta, RichTextDeltaBuilder}; /// - /// let mut attribute = RichTextAttribute::Bold(true); + /// let mut attribute = TextAttribute::Bold(true); /// let delta = RichTextDeltaBuilder::new().retain_with_attributes(7, attribute.into()).build(); /// /// assert_eq!(delta.json_str(), r#"[{"retain":7,"attributes":{"bold":true}}]"#); @@ -109,7 +109,7 @@ where /// /// ``` /// use lib_ot::core::{OperationTransform, TextDeltaBuilder}; - /// use lib_ot::rich_text::{RichTextAttribute, RichTextDeltaBuilder}; + /// use lib_ot::rich_text::{TextAttribute, RichTextDeltaBuilder}; /// let delta = TextDeltaBuilder::new() /// .retain(3) /// .trim() @@ -117,7 +117,7 @@ where /// assert_eq!(delta.ops.len(), 0); /// /// let delta = RichTextDeltaBuilder::new() - /// .retain_with_attributes(3, RichTextAttribute::Bold(true).into()) + /// .retain_with_attributes(3, TextAttribute::Bold(true).into()) /// .trim() /// .build(); /// assert_eq!(delta.ops.len(), 1); diff --git a/shared-lib/lib-ot/src/core/delta/iterator.rs b/shared-lib/lib-ot/src/core/delta/iterator.rs index 7997d23bae..53fb4f879b 100644 --- a/shared-lib/lib-ot/src/core/delta/iterator.rs +++ b/shared-lib/lib-ot/src/core/delta/iterator.rs @@ -2,7 +2,7 @@ use super::cursor::*; use crate::core::delta::{Delta, NEW_LINE}; use crate::core::interval::Interval; use crate::core::operation::{Attributes, Operation}; -use crate::rich_text::RichTextAttributes; +use crate::rich_text::TextAttributes; use std::ops::{Deref, DerefMut}; pub(crate) const MAX_IV_LEN: usize = i32::MAX as usize; @@ -132,7 +132,7 @@ where } } -pub fn is_empty_line_at_index(delta: &Delta, index: usize) -> bool { +pub fn is_empty_line_at_index(delta: &Delta, index: usize) -> bool { let mut iter = DeltaIterator::new(delta); let (prev, next) = (iter.next_op_with_len(index), iter.next_op()); if prev.is_none() { diff --git a/shared-lib/lib-ot/src/core/document/attributes.rs b/shared-lib/lib-ot/src/core/document/attributes.rs index ca5878fb4b..5ad89fbee9 100644 --- a/shared-lib/lib-ot/src/core/document/attributes.rs +++ b/shared-lib/lib-ot/src/core/document/attributes.rs @@ -1,10 +1,12 @@ +use crate::core::OperationTransform; +use crate::errors::OTError; use serde::{Deserialize, Serialize}; use std::collections::HashMap; -pub type AttributeMap = HashMap>; +pub type AttributeMap = HashMap; #[derive(Clone, Serialize, Deserialize, Eq, PartialEq, Debug)] -pub struct NodeAttributes(pub AttributeMap); +pub struct NodeAttributes(AttributeMap); impl Default for NodeAttributes { fn default() -> Self { @@ -31,19 +33,120 @@ impl NodeAttributes { NodeAttributes(HashMap::new()) } + pub fn from_value(attribute_map: AttributeMap) -> Self { + Self(attribute_map) + } + pub fn to_inner(&self) -> AttributeMap { self.0.clone() } - pub fn compose(a: &NodeAttributes, b: &NodeAttributes) -> NodeAttributes { - let mut new_map: AttributeMap = b.0.clone(); + pub fn insert>(&mut self, key: K, value: V) { + self.0.insert(key.to_string(), value.into()); + } - for (key, value) in &a.0 { - if b.0.contains_key(key.as_str()) { - new_map.insert(key.into(), value.clone()); - } - } - - NodeAttributes(new_map) + pub fn delete(&mut self, key: &AttributeKey) { + self.insert(key.clone(), AttributeValue(None)); + } +} + +impl OperationTransform for NodeAttributes { + fn compose(&self, other: &Self) -> Result + where + Self: Sized, + { + let mut attributes = self.clone(); + attributes.0.extend(other.clone().0); + Ok(attributes) + } + + fn transform(&self, other: &Self) -> Result<(Self, Self), OTError> + where + Self: Sized, + { + let a = self.iter().fold(NodeAttributes::new(), |mut new_attributes, (k, v)| { + if !other.contains_key(k) { + new_attributes.insert(k.clone(), v.clone()); + } + new_attributes + }); + + let b = other.iter().fold(NodeAttributes::new(), |mut new_attributes, (k, v)| { + if !self.contains_key(k) { + new_attributes.insert(k.clone(), v.clone()); + } + new_attributes + }); + + Ok((a, b)) + } + + fn invert(&self, other: &Self) -> Self { + let base_inverted = other.iter().fold(NodeAttributes::new(), |mut attributes, (k, v)| { + if other.get(k) != self.get(k) && self.contains_key(k) { + attributes.insert(k.clone(), v.clone()); + } + attributes + }); + + self.iter().fold(base_inverted, |mut attributes, (k, _)| { + if other.get(k) != self.get(k) && !other.contains_key(k) { + attributes.delete(k); + } + attributes + }) + } +} + +pub type AttributeKey = String; + +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub struct AttributeValue(pub Option); + +impl std::convert::From<&usize> for AttributeValue { + fn from(val: &usize) -> Self { + AttributeValue::from(*val) + } +} + +impl std::convert::From for AttributeValue { + fn from(val: usize) -> Self { + if val > 0_usize { + AttributeValue(Some(format!("{}", val))) + } else { + AttributeValue(None) + } + } +} + +impl std::convert::From<&str> for AttributeValue { + fn from(val: &str) -> Self { + val.to_owned().into() + } +} + +impl std::convert::From for AttributeValue { + fn from(val: String) -> Self { + if val.is_empty() { + AttributeValue(None) + } else { + AttributeValue(Some(val)) + } + } +} + +impl std::convert::From<&bool> for AttributeValue { + fn from(val: &bool) -> Self { + AttributeValue::from(*val) + } +} + +impl std::convert::From for AttributeValue { + fn from(val: bool) -> Self { + let val = match val { + true => Some("true".to_owned()), + false => None, + }; + AttributeValue(val) } } diff --git a/shared-lib/lib-ot/src/core/document/mod.rs b/shared-lib/lib-ot/src/core/document/mod.rs index 2dde3ef3e9..a0eced6c24 100644 --- a/shared-lib/lib-ot/src/core/document/mod.rs +++ b/shared-lib/lib-ot/src/core/document/mod.rs @@ -1,14 +1,14 @@ #![allow(clippy::module_inception)] mod attributes; -mod document; -mod document_operation; mod node; -mod position; +mod node_tree; +mod operation; +mod path; mod transaction; pub use attributes::*; -pub use document::*; -pub use document_operation::*; pub use node::*; -pub use position::*; +pub use node_tree::*; +pub use operation::*; +pub use path::*; pub use transaction::*; diff --git a/shared-lib/lib-ot/src/core/document/node.rs b/shared-lib/lib-ot/src/core/document/node.rs index 9115f656f4..8b2daec19b 100644 --- a/shared-lib/lib-ot/src/core/document/node.rs +++ b/shared-lib/lib-ot/src/core/document/node.rs @@ -18,8 +18,28 @@ impl NodeData { } } +impl std::convert::From for NodeData { + fn from(node: Node) -> Self { + Self { + node_type: node.note_type, + attributes: node.attributes, + delta: node.delta, + } + } +} + +impl std::convert::From<&Node> for NodeData { + fn from(node: &Node) -> Self { + Self { + node_type: node.note_type.clone(), + attributes: node.attributes.clone(), + delta: node.delta.clone(), + } + } +} + #[derive(Clone, Serialize, Deserialize, Eq, PartialEq)] -pub struct NodeSubTree { +pub struct Node { #[serde(rename = "type")] pub note_type: String, @@ -29,24 +49,16 @@ pub struct NodeSubTree { pub delta: Option, #[serde(skip_serializing_if = "Vec::is_empty")] - pub children: Vec, + pub children: Vec, } -impl NodeSubTree { - pub fn new(node_type: &str) -> NodeSubTree { - NodeSubTree { +impl Node { + pub fn new(node_type: &str) -> Node { + Node { note_type: node_type.into(), attributes: NodeAttributes::new(), delta: None, children: Vec::new(), } } - - pub fn to_node_data(&self) -> NodeData { - NodeData { - node_type: self.note_type.clone(), - attributes: self.attributes.clone(), - delta: self.delta.clone(), - } - } } diff --git a/shared-lib/lib-ot/src/core/document/document.rs b/shared-lib/lib-ot/src/core/document/node_tree.rs similarity index 51% rename from shared-lib/lib-ot/src/core/document/document.rs rename to shared-lib/lib-ot/src/core/document/node_tree.rs index 59758c7ca9..2d1483d59f 100644 --- a/shared-lib/lib-ot/src/core/document/document.rs +++ b/shared-lib/lib-ot/src/core/document/node_tree.rs @@ -1,42 +1,43 @@ -use crate::core::document::position::Path; -use crate::core::{ - DocumentOperation, NodeAttributes, NodeData, NodeSubTree, OperationTransform, TextDelta, Transaction, -}; +use crate::core::document::path::Path; +use crate::core::{Node, NodeAttributes, NodeData, NodeOperation, OperationTransform, TextDelta, Transaction}; use crate::errors::{ErrorBuilder, OTError, OTErrorCode}; use indextree::{Arena, Children, FollowingSiblings, NodeId}; -pub struct DocumentTree { +pub struct NodeTree { arena: Arena, root: NodeId, } -impl Default for DocumentTree { +impl Default for NodeTree { fn default() -> Self { Self::new() } } -impl DocumentTree { - pub fn new() -> DocumentTree { +impl NodeTree { + pub fn new() -> NodeTree { let mut arena = Arena::new(); - let root = arena.new_node(NodeData::new("root")); - DocumentTree { arena, root } + NodeTree { arena, root } + } + + pub fn get_node_data(&self, node_id: NodeId) -> Option<&NodeData> { + Some(self.arena.get(node_id)?.get()) } /// /// # Examples /// /// ``` - /// use lib_ot::core::{DocumentOperation, DocumentTree, NodeSubTree, Path}; - /// let nodes = vec![NodeSubTree::new("text")]; + /// use lib_ot::core::{NodeOperation, NodeTree, Node, Path}; + /// let nodes = vec![Node::new("text")]; /// let root_path: Path = vec![0].into(); - /// let op = DocumentOperation::Insert {path: root_path.clone(),nodes }; + /// let op = NodeOperation::Insert {path: root_path.clone(),nodes }; /// - /// let mut document = DocumentTree::new(); - /// document.apply_op(&op).unwrap(); - /// let node_id = document.node_at_path(&root_path).unwrap(); - /// let node_path = document.path_of_node(node_id); + /// let mut node_tree = NodeTree::new(); + /// node_tree.apply_op(&op).unwrap(); + /// let node_id = node_tree.node_at_path(&root_path).unwrap(); + /// let node_path = node_tree.path_of_node(node_id); /// debug_assert_eq!(node_path, root_path); /// ``` pub fn node_at_path>(&self, path: T) -> Option { @@ -47,23 +48,20 @@ impl DocumentTree { let mut iterate_node = self.root; for id in path.iter() { - iterate_node = self.child_from_node_with_index(iterate_node, *id)?; + iterate_node = self.child_from_node_at_index(iterate_node, *id)?; } Some(iterate_node) } pub fn path_of_node(&self, node_id: NodeId) -> Path { - let mut path: Vec = Vec::new(); - let mut ancestors = node_id.ancestors(&self.arena).skip(1); + let mut path = vec![]; let mut current_node = node_id; - let mut parent = ancestors.next(); - - while parent.is_some() { - let parent_node = parent.unwrap(); + // Use .skip(1) on the ancestors iterator to skip the root node. + let mut ancestors = node_id.ancestors(&self.arena).skip(1); + while let Some(parent_node) = ancestors.next() { let counter = self.index_of_node(parent_node, current_node); path.push(counter); current_node = parent_node; - parent = ancestors.next(); } Path(path) @@ -71,14 +69,11 @@ impl DocumentTree { fn index_of_node(&self, parent_node: NodeId, child_node: NodeId) -> usize { let mut counter: usize = 0; - let mut children_iterator = parent_node.children(&self.arena); - let mut node = children_iterator.next(); - while node.is_some() { - if node.unwrap() == child_node { + let mut iter = parent_node.children(&self.arena); + while let Some(node) = iter.next() { + if node == child_node { return counter; } - - node = children_iterator.next(); counter += 1; } @@ -88,7 +83,7 @@ impl DocumentTree { /// /// # Arguments /// - /// * `at_node`: + /// * `node_id`: /// * `index`: /// /// returns: Option @@ -96,19 +91,19 @@ impl DocumentTree { /// # Examples /// /// ``` - /// use lib_ot::core::{DocumentOperation, DocumentTree, NodeSubTree, Path}; - /// let node = NodeSubTree::new("text"); + /// use lib_ot::core::{NodeOperation, NodeTree, Node, Path}; + /// let node = Node::new("text"); /// let inserted_path: Path = vec![0].into(); /// - /// let mut document = DocumentTree::new(); - /// document.apply_op(&DocumentOperation::Insert {path: inserted_path.clone(),nodes: vec![node.clone()] }).unwrap(); + /// let mut node_tree = NodeTree::new(); + /// node_tree.apply_op(&NodeOperation::Insert {path: inserted_path.clone(),nodes: vec![node.clone()] }).unwrap(); /// - /// let inserted_note = document.node_at_path(&inserted_path).unwrap(); - /// let inserted_data = document.get_node_data(inserted_note).unwrap(); + /// let inserted_note = node_tree.node_at_path(&inserted_path).unwrap(); + /// let inserted_data = node_tree.get_node_data(inserted_note).unwrap(); /// assert_eq!(inserted_data.node_type, node.note_type); /// ``` - pub fn child_from_node_with_index(&self, at_node: NodeId, index: usize) -> Option { - let children = at_node.children(&self.arena); + pub fn child_from_node_at_index(&self, node_id: NodeId, index: usize) -> Option { + let children = node_id.children(&self.arena); for (counter, child) in children.enumerate() { if counter == index { return Some(child); @@ -122,10 +117,6 @@ impl DocumentTree { node_id.children(&self.arena) } - pub fn get_node_data(&self, node_id: NodeId) -> Option<&NodeData> { - Some(self.arena.get(node_id)?.get()) - } - /// /// # Arguments /// @@ -151,16 +142,16 @@ impl DocumentTree { Ok(()) } - pub fn apply_op(&mut self, op: &DocumentOperation) -> Result<(), OTError> { + pub fn apply_op(&mut self, op: &NodeOperation) -> Result<(), OTError> { match op { - DocumentOperation::Insert { path, nodes } => self.apply_insert(path, nodes), - DocumentOperation::Update { path, attributes, .. } => self.apply_update(path, attributes), - DocumentOperation::Delete { path, nodes } => self.apply_delete(path, nodes.len()), - DocumentOperation::TextEdit { path, delta, .. } => self.apply_text_edit(path, delta), + NodeOperation::Insert { path, nodes } => self.insert_nodes(path, nodes), + NodeOperation::Update { path, attributes, .. } => self.update_node(path, attributes), + NodeOperation::Delete { path, nodes } => self.delete_node(path, nodes), + NodeOperation::TextEdit { path, delta, .. } => self.update_delta(path, delta), } } - fn apply_insert(&mut self, path: &Path, nodes: &[NodeSubTree]) -> Result<(), OTError> { + fn insert_nodes(&mut self, path: &Path, nodes: &[Node]) -> Result<(), OTError> { debug_assert!(!path.is_empty()); if path.is_empty() { return Err(OTErrorCode::PathIsEmpty.into()); @@ -172,27 +163,22 @@ impl DocumentTree { .node_at_path(parent_path) .ok_or_else(|| ErrorBuilder::new(OTErrorCode::PathNotFound).build())?; - self.insert_child_at_index(parent_node, last_index, nodes) + self.insert_nodes_at_index(parent_node, last_index, nodes) } - fn insert_child_at_index( - &mut self, - parent: NodeId, - index: usize, - insert_children: &[NodeSubTree], - ) -> Result<(), OTError> { + fn insert_nodes_at_index(&mut self, parent: NodeId, index: usize, insert_children: &[Node]) -> Result<(), OTError> { if index == 0 && parent.children(&self.arena).next().is_none() { - self.append_subtree(&parent, insert_children); + self.append_nodes(&parent, insert_children); return Ok(()); } if index == parent.children(&self.arena).count() { - self.append_subtree(&parent, insert_children); + self.append_nodes(&parent, insert_children); return Ok(()); } let node_to_insert = self - .child_from_node_with_index(parent, index) + .child_from_node_at_index(parent, index) .ok_or_else(|| ErrorBuilder::new(OTErrorCode::PathNotFound).build())?; self.insert_subtree_before(&node_to_insert, insert_children); @@ -200,46 +186,37 @@ impl DocumentTree { } // recursive append the subtrees to the node - fn append_subtree(&mut self, parent: &NodeId, insert_children: &[NodeSubTree]) { + fn append_nodes(&mut self, parent: &NodeId, insert_children: &[Node]) { for child in insert_children { - let child_id = self.arena.new_node(child.to_node_data()); + let child_id = self.arena.new_node(child.into()); parent.append(child_id, &mut self.arena); - self.append_subtree(&child_id, &child.children); + self.append_nodes(&child_id, &child.children); } } - fn insert_subtree_before(&mut self, before: &NodeId, insert_children: &[NodeSubTree]) { + fn insert_subtree_before(&mut self, before: &NodeId, insert_children: &[Node]) { for child in insert_children { - let child_id = self.arena.new_node(child.to_node_data()); + let child_id = self.arena.new_node(child.into()); before.insert_before(child_id, &mut self.arena); - self.append_subtree(&child_id, &child.children); + self.append_nodes(&child_id, &child.children); } } - fn apply_update(&mut self, path: &Path, attributes: &NodeAttributes) -> Result<(), OTError> { - let update_node = self - .node_at_path(path) - .ok_or_else(|| ErrorBuilder::new(OTErrorCode::PathNotFound).build())?; - let node_data = self.arena.get_mut(update_node).unwrap(); - let new_node = { - let old_attributes = &node_data.get().attributes; - let new_attributes = NodeAttributes::compose(old_attributes, attributes); - NodeData { - attributes: new_attributes, - ..node_data.get().clone() - } - }; - *node_data.get_mut() = new_node; - Ok(()) + fn update_node(&mut self, path: &Path, attributes: &NodeAttributes) -> Result<(), OTError> { + self.mut_node_at_path(path, |node_data| { + let new_attributes = NodeAttributes::compose(&node_data.attributes, attributes)?; + node_data.attributes = new_attributes; + Ok(()) + }) } - fn apply_delete(&mut self, path: &Path, len: usize) -> Result<(), OTError> { + fn delete_node(&mut self, path: &Path, nodes: &[Node]) -> Result<(), OTError> { let mut update_node = self .node_at_path(path) .ok_or_else(|| ErrorBuilder::new(OTErrorCode::PathNotFound).build())?; - for _ in 0..len { + for _ in 0..nodes.len() { let next = update_node.following_siblings(&self.arena).next(); update_node.remove_subtree(&mut self.arena); if let Some(next_id) = next { @@ -251,22 +228,35 @@ impl DocumentTree { Ok(()) } - fn apply_text_edit(&mut self, path: &Path, delta: &TextDelta) -> Result<(), OTError> { - let edit_node = self + fn update_delta(&mut self, path: &Path, delta: &TextDelta) -> Result<(), OTError> { + self.mut_node_at_path(path, |node_data| { + if node_data.delta.is_none() { + let msg = format!("The delta of the node at path:{:?} should not be empty", path); + tracing::error!("{}", msg); + return Err(OTError::new(OTErrorCode::UnexpectedEmpty, msg)); + } + let new_delta = node_data.delta.as_ref().unwrap().compose(delta)?; + let _ = node_data.delta = Some(new_delta); + Ok(()) + })?; + + Ok(()) + } + + fn mut_node_at_path(&mut self, path: &Path, f: F) -> Result<(), OTError> + where + F: Fn(&mut NodeData) -> Result<(), OTError>, + { + let node_id = self .node_at_path(path) .ok_or_else(|| ErrorBuilder::new(OTErrorCode::PathNotFound).build())?; - let node_data = self.arena.get_mut(edit_node).unwrap(); - let new_delta = if let Some(old_delta) = &node_data.get().delta { - Some(old_delta.compose(delta)?) - } else { - None - }; - if let Some(new_delta) = new_delta { - *node_data.get_mut() = NodeData { - delta: Some(new_delta), - ..node_data.get().clone() - }; - }; + match self.arena.get_mut(node_id) { + None => tracing::warn!("The path: {:?} does not contain any nodes", path), + Some(node) => { + let node_data = node.get_mut(); + let _ = f(node_data)?; + } + } Ok(()) } } diff --git a/shared-lib/lib-ot/src/core/document/document_operation.rs b/shared-lib/lib-ot/src/core/document/operation.rs similarity index 52% rename from shared-lib/lib-ot/src/core/document/document_operation.rs rename to shared-lib/lib-ot/src/core/document/operation.rs index 6e34c8cb77..be250a8a19 100644 --- a/shared-lib/lib-ot/src/core/document/document_operation.rs +++ b/shared-lib/lib-ot/src/core/document/operation.rs @@ -1,11 +1,11 @@ -use crate::core::document::position::Path; -use crate::core::{NodeAttributes, NodeSubTree, TextDelta}; +use crate::core::document::path::Path; +use crate::core::{Node, NodeAttributes, TextDelta}; #[derive(Clone, serde::Serialize, serde::Deserialize)] #[serde(tag = "op")] -pub enum DocumentOperation { +pub enum NodeOperation { #[serde(rename = "insert")] - Insert { path: Path, nodes: Vec }, + Insert { path: Path, nodes: Vec }, #[serde(rename = "update")] Update { path: Path, @@ -14,7 +14,7 @@ pub enum DocumentOperation { old_attributes: NodeAttributes, }, #[serde(rename = "delete")] - Delete { path: Path, nodes: Vec }, + Delete { path: Path, nodes: Vec }, #[serde(rename = "text-edit")] TextEdit { path: Path, @@ -23,74 +23,74 @@ pub enum DocumentOperation { }, } -impl DocumentOperation { +impl NodeOperation { pub fn path(&self) -> &Path { match self { - DocumentOperation::Insert { path, .. } => path, - DocumentOperation::Update { path, .. } => path, - DocumentOperation::Delete { path, .. } => path, - DocumentOperation::TextEdit { path, .. } => path, + NodeOperation::Insert { path, .. } => path, + NodeOperation::Update { path, .. } => path, + NodeOperation::Delete { path, .. } => path, + NodeOperation::TextEdit { path, .. } => path, } } - pub fn invert(&self) -> DocumentOperation { + pub fn invert(&self) -> NodeOperation { match self { - DocumentOperation::Insert { path, nodes } => DocumentOperation::Delete { + NodeOperation::Insert { path, nodes } => NodeOperation::Delete { path: path.clone(), nodes: nodes.clone(), }, - DocumentOperation::Update { + NodeOperation::Update { path, attributes, old_attributes, - } => DocumentOperation::Update { + } => NodeOperation::Update { path: path.clone(), attributes: old_attributes.clone(), old_attributes: attributes.clone(), }, - DocumentOperation::Delete { path, nodes } => DocumentOperation::Insert { + NodeOperation::Delete { path, nodes } => NodeOperation::Insert { path: path.clone(), nodes: nodes.clone(), }, - DocumentOperation::TextEdit { path, delta, inverted } => DocumentOperation::TextEdit { + NodeOperation::TextEdit { path, delta, inverted } => NodeOperation::TextEdit { path: path.clone(), delta: inverted.clone(), inverted: delta.clone(), }, } } - pub fn clone_with_new_path(&self, path: Path) -> DocumentOperation { + pub fn clone_with_new_path(&self, path: Path) -> NodeOperation { match self { - DocumentOperation::Insert { nodes, .. } => DocumentOperation::Insert { + NodeOperation::Insert { nodes, .. } => NodeOperation::Insert { path, nodes: nodes.clone(), }, - DocumentOperation::Update { + NodeOperation::Update { attributes, old_attributes, .. - } => DocumentOperation::Update { + } => NodeOperation::Update { path, attributes: attributes.clone(), old_attributes: old_attributes.clone(), }, - DocumentOperation::Delete { nodes, .. } => DocumentOperation::Delete { + NodeOperation::Delete { nodes, .. } => NodeOperation::Delete { path, nodes: nodes.clone(), }, - DocumentOperation::TextEdit { delta, inverted, .. } => DocumentOperation::TextEdit { + NodeOperation::TextEdit { delta, inverted, .. } => NodeOperation::TextEdit { path, delta: delta.clone(), inverted: inverted.clone(), }, } } - pub fn transform(a: &DocumentOperation, b: &DocumentOperation) -> DocumentOperation { + pub fn transform(a: &NodeOperation, b: &NodeOperation) -> NodeOperation { match a { - DocumentOperation::Insert { path: a_path, nodes } => { + NodeOperation::Insert { path: a_path, nodes } => { let new_path = Path::transform(a_path, b.path(), nodes.len() as i64); b.clone_with_new_path(new_path) } - DocumentOperation::Delete { path: a_path, nodes } => { + NodeOperation::Delete { path: a_path, nodes } => { let new_path = Path::transform(a_path, b.path(), nodes.len() as i64); b.clone_with_new_path(new_path) } @@ -101,61 +101,12 @@ impl DocumentOperation { #[cfg(test)] mod tests { - use crate::core::{Delta, DocumentOperation, NodeAttributes, NodeSubTree, Path}; - - #[test] - fn test_transform_path_1() { - assert_eq!( - { Path::transform(&Path(vec![0, 1]), &Path(vec![0, 1]), 1) }.0, - vec![0, 2] - ); - } - - #[test] - fn test_transform_path_2() { - assert_eq!( - { Path::transform(&Path(vec![0, 1]), &Path(vec![0, 2]), 1) }.0, - vec![0, 3] - ); - } - - #[test] - fn test_transform_path_3() { - assert_eq!( - { Path::transform(&Path(vec![0, 1]), &Path(vec![0, 2, 7, 8, 9]), 1) }.0, - vec![0, 3, 7, 8, 9] - ); - } - - #[test] - fn test_transform_path_not_changed() { - assert_eq!( - { Path::transform(&Path(vec![0, 1, 2]), &Path(vec![0, 0, 7, 8, 9]), 1) }.0, - vec![0, 0, 7, 8, 9] - ); - assert_eq!( - { Path::transform(&Path(vec![0, 1, 2]), &Path(vec![0, 1]), 1) }.0, - vec![0, 1] - ); - assert_eq!( - { Path::transform(&Path(vec![1, 1]), &Path(vec![1, 0]), 1) }.0, - vec![1, 0] - ); - } - - #[test] - fn test_transform_delta() { - assert_eq!( - { Path::transform(&Path(vec![0, 1]), &Path(vec![0, 1]), 5) }.0, - vec![0, 6] - ); - } - + use crate::core::{Delta, Node, NodeAttributes, NodeOperation, Path}; #[test] fn test_serialize_insert_operation() { - let insert = DocumentOperation::Insert { + let insert = NodeOperation::Insert { path: Path(vec![0, 1]), - nodes: vec![NodeSubTree::new("text")], + nodes: vec![Node::new("text")], }; let result = serde_json::to_string(&insert).unwrap(); assert_eq!( @@ -166,13 +117,13 @@ mod tests { #[test] fn test_serialize_insert_sub_trees() { - let insert = DocumentOperation::Insert { + let insert = NodeOperation::Insert { path: Path(vec![0, 1]), - nodes: vec![NodeSubTree { + nodes: vec![Node { note_type: "text".into(), attributes: NodeAttributes::new(), delta: None, - children: vec![NodeSubTree::new("text")], + children: vec![Node::new("text")], }], }; let result = serde_json::to_string(&insert).unwrap(); @@ -184,7 +135,7 @@ mod tests { #[test] fn test_serialize_update_operation() { - let insert = DocumentOperation::Update { + let insert = NodeOperation::Update { path: Path(vec![0, 1]), attributes: NodeAttributes::new(), old_attributes: NodeAttributes::new(), @@ -198,7 +149,7 @@ mod tests { #[test] fn test_serialize_text_edit_operation() { - let insert = DocumentOperation::TextEdit { + let insert = NodeOperation::TextEdit { path: Path(vec![0, 1]), delta: Delta::new(), inverted: Delta::new(), diff --git a/shared-lib/lib-ot/src/core/document/position.rs b/shared-lib/lib-ot/src/core/document/path.rs similarity index 61% rename from shared-lib/lib-ot/src/core/document/position.rs rename to shared-lib/lib-ot/src/core/document/path.rs index c098096569..ed1770d290 100644 --- a/shared-lib/lib-ot/src/core/document/position.rs +++ b/shared-lib/lib-ot/src/core/document/path.rs @@ -76,3 +76,52 @@ impl Path { Path(prefix) } } + +#[cfg(test)] +mod tests { + use crate::core::Path; + #[test] + fn path_transform_test_1() { + assert_eq!( + { Path::transform(&Path(vec![0, 1]), &Path(vec![0, 1]), 1) }.0, + vec![0, 2] + ); + + assert_eq!( + { Path::transform(&Path(vec![0, 1]), &Path(vec![0, 1]), 5) }.0, + vec![0, 6] + ); + } + + #[test] + fn path_transform_test_2() { + assert_eq!( + { Path::transform(&Path(vec![0, 1]), &Path(vec![0, 2]), 1) }.0, + vec![0, 3] + ); + } + + #[test] + fn path_transform_test_3() { + assert_eq!( + { Path::transform(&Path(vec![0, 1]), &Path(vec![0, 2, 7, 8, 9]), 1) }.0, + vec![0, 3, 7, 8, 9] + ); + } + + #[test] + fn path_transform_no_changed_test() { + assert_eq!( + { Path::transform(&Path(vec![0, 1, 2]), &Path(vec![0, 0, 7, 8, 9]), 1) }.0, + vec![0, 0, 7, 8, 9] + ); + assert_eq!( + { Path::transform(&Path(vec![0, 1, 2]), &Path(vec![0, 1]), 1) }.0, + vec![0, 1] + ); + assert_eq!( + { Path::transform(&Path(vec![1, 1]), &Path(vec![1, 0]), 1) }.0, + vec![1, 0] + ); + } +} diff --git a/shared-lib/lib-ot/src/core/document/transaction.rs b/shared-lib/lib-ot/src/core/document/transaction.rs index a99ab66dac..755e9419de 100644 --- a/shared-lib/lib-ot/src/core/document/transaction.rs +++ b/shared-lib/lib-ot/src/core/document/transaction.rs @@ -1,26 +1,26 @@ -use crate::core::document::position::Path; -use crate::core::{AttributeMap, DocumentOperation, DocumentTree, NodeAttributes, NodeSubTree}; +use crate::core::document::path::Path; +use crate::core::{Node, NodeAttributes, NodeOperation, NodeTree}; use indextree::NodeId; pub struct Transaction { - pub operations: Vec, + pub operations: Vec, } impl Transaction { - fn new(operations: Vec) -> Transaction { + fn new(operations: Vec) -> Transaction { Transaction { operations } } } pub struct TransactionBuilder<'a> { - document: &'a DocumentTree, - operations: Vec, + node_tree: &'a NodeTree, + operations: Vec, } impl<'a> TransactionBuilder<'a> { - pub fn new(document: &'a DocumentTree) -> TransactionBuilder { + pub fn new(node_tree: &'a NodeTree) -> TransactionBuilder { TransactionBuilder { - document, + node_tree, operations: Vec::new(), } } @@ -38,18 +38,18 @@ impl<'a> TransactionBuilder<'a> { /// // -- 0 (root) /// // 0 -- text_1 /// // 1 -- text_2 - /// use lib_ot::core::{DocumentTree, NodeSubTree, TransactionBuilder}; - /// let mut document = DocumentTree::new(); - /// let transaction = TransactionBuilder::new(&document) - /// .insert_nodes_at_path(0,vec![ NodeSubTree::new("text_1"), NodeSubTree::new("text_2")]) + /// use lib_ot::core::{NodeTree, Node, TransactionBuilder}; + /// let mut node_tree = NodeTree::new(); + /// let transaction = TransactionBuilder::new(&node_tree) + /// .insert_nodes_at_path(0,vec![ Node::new("text_1"), Node::new("text_2")]) /// .finalize(); - /// document.apply(transaction).unwrap(); + /// node_tree.apply(transaction).unwrap(); /// - /// document.node_at_path(vec![0, 0]); + /// node_tree.node_at_path(vec![0, 0]); /// ``` /// - pub fn insert_nodes_at_path>(self, path: T, nodes: Vec) -> Self { - self.push(DocumentOperation::Insert { + pub fn insert_nodes_at_path>(self, path: T, nodes: Vec) -> Self { + self.push(NodeOperation::Insert { path: path.into(), nodes, }) @@ -68,36 +68,34 @@ impl<'a> TransactionBuilder<'a> { /// // 0 /// // -- 0 /// // |-- text - /// use lib_ot::core::{DocumentTree, NodeSubTree, TransactionBuilder}; - /// let mut document = DocumentTree::new(); - /// let transaction = TransactionBuilder::new(&document) - /// .insert_node_at_path(0, NodeSubTree::new("text")) + /// use lib_ot::core::{NodeTree, Node, TransactionBuilder}; + /// let mut node_tree = NodeTree::new(); + /// let transaction = TransactionBuilder::new(&node_tree) + /// .insert_node_at_path(0, Node::new("text")) /// .finalize(); - /// document.apply(transaction).unwrap(); + /// node_tree.apply(transaction).unwrap(); /// ``` /// - pub fn insert_node_at_path>(self, path: T, node: NodeSubTree) -> Self { + pub fn insert_node_at_path>(self, path: T, node: Node) -> Self { self.insert_nodes_at_path(path, vec![node]) } - pub fn update_attributes_at_path(self, path: &Path, attributes: AttributeMap) -> Self { - let mut old_attributes: AttributeMap = AttributeMap::new(); - let node = self.document.node_at_path(path).unwrap(); - let node_data = self.document.get_node_data(node).unwrap(); + pub fn update_attributes_at_path(self, path: &Path, attributes: NodeAttributes) -> Self { + let mut old_attributes = NodeAttributes::new(); + let node = self.node_tree.node_at_path(path).unwrap(); + let node_data = self.node_tree.get_node_data(node).unwrap(); for key in attributes.keys() { let old_attrs = &node_data.attributes; - let old_value = match old_attrs.0.get(key.as_str()) { - Some(value) => value.clone(), - None => None, - }; - old_attributes.insert(key.clone(), old_value); + if let Some(value) = old_attrs.get(key.as_str()) { + old_attributes.insert(key.clone(), value.clone()); + } } - self.push(DocumentOperation::Update { + self.push(NodeOperation::Update { path: path.clone(), - attributes: NodeAttributes(attributes), - old_attributes: NodeAttributes(old_attributes), + attributes, + old_attributes, }) } @@ -106,29 +104,29 @@ impl<'a> TransactionBuilder<'a> { } pub fn delete_nodes_at_path(mut self, path: &Path, length: usize) -> Self { - let mut node = self.document.node_at_path(path).unwrap(); + let mut node = self.node_tree.node_at_path(path).unwrap(); let mut deleted_nodes = vec![]; for _ in 0..length { deleted_nodes.push(self.get_deleted_nodes(node)); - node = self.document.following_siblings(node).next().unwrap(); + node = self.node_tree.following_siblings(node).next().unwrap(); } - self.operations.push(DocumentOperation::Delete { + self.operations.push(NodeOperation::Delete { path: path.clone(), nodes: deleted_nodes, }); self } - fn get_deleted_nodes(&self, node_id: NodeId) -> NodeSubTree { - let node_data = self.document.get_node_data(node_id).unwrap(); + fn get_deleted_nodes(&self, node_id: NodeId) -> Node { + let node_data = self.node_tree.get_node_data(node_id).unwrap(); let mut children = vec![]; - self.document.children_from_node(node_id).for_each(|child_id| { + self.node_tree.children_from_node(node_id).for_each(|child_id| { children.push(self.get_deleted_nodes(child_id)); }); - NodeSubTree { + Node { note_type: node_data.node_type.clone(), attributes: node_data.attributes.clone(), delta: node_data.delta.clone(), @@ -136,7 +134,7 @@ impl<'a> TransactionBuilder<'a> { } } - pub fn push(mut self, op: DocumentOperation) -> Self { + pub fn push(mut self, op: NodeOperation) -> Self { self.operations.push(op); self } diff --git a/shared-lib/lib-ot/src/core/operation/builder.rs b/shared-lib/lib-ot/src/core/operation/builder.rs index c4f9cc8277..b5a06484eb 100644 --- a/shared-lib/lib-ot/src/core/operation/builder.rs +++ b/shared-lib/lib-ot/src/core/operation/builder.rs @@ -1,7 +1,7 @@ use crate::core::operation::{Attributes, Operation, PhantomAttributes}; -use crate::rich_text::RichTextAttributes; +use crate::rich_text::TextAttributes; -pub type RichTextOpBuilder = OperationsBuilder; +pub type RichTextOpBuilder = OperationsBuilder; pub type PlainTextOpBuilder = OperationsBuilder; #[derive(Default)] diff --git a/shared-lib/lib-ot/src/core/operation/operation.rs b/shared-lib/lib-ot/src/core/operation/operation.rs index 4bacd1ea7d..48899ef8ce 100644 --- a/shared-lib/lib-ot/src/core/operation/operation.rs +++ b/shared-lib/lib-ot/src/core/operation/operation.rs @@ -64,7 +64,7 @@ pub trait OperationTransform { fn invert(&self, other: &Self) -> Self; } -/// Each operation can carry attributes. For example, the [RichTextAttributes] 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 }. /// ///Because [Operation] is generic over the T, so you must specify the T. For example, the [TextDelta] uses diff --git a/shared-lib/lib-ot/src/errors.rs b/shared-lib/lib-ot/src/errors.rs index 449c662883..fe2a03b206 100644 --- a/shared-lib/lib-ot/src/errors.rs +++ b/shared-lib/lib-ot/src/errors.rs @@ -25,11 +25,8 @@ impl std::convert::From for OTError { } impl OTError { - pub fn new(code: OTErrorCode, msg: &str) -> OTError { - Self { - code, - msg: msg.to_owned(), - } + pub fn new(code: OTErrorCode, msg: String) -> OTError { + Self { code, msg } } pub fn context(mut self, error: T) -> Self { @@ -76,6 +73,7 @@ pub enum OTErrorCode { Internal, PathNotFound, PathIsEmpty, + UnexpectedEmpty, } pub struct ErrorBuilder { @@ -105,6 +103,6 @@ impl ErrorBuilder { } pub fn build(mut self) -> OTError { - OTError::new(self.code, &self.msg.take().unwrap_or_else(|| "".to_owned())) + OTError::new(self.code, self.msg.take().unwrap_or_else(|| "".to_owned())) } } diff --git a/shared-lib/lib-ot/src/rich_text/attributes.rs b/shared-lib/lib-ot/src/rich_text/attributes.rs index be3b1bbf59..f862dab4f3 100644 --- a/shared-lib/lib-ot/src/rich_text/attributes.rs +++ b/shared-lib/lib-ot/src/rich_text/attributes.rs @@ -10,19 +10,19 @@ use std::{ }; use strum_macros::Display; -pub type RichTextOperation = Operation; +pub type RichTextOperation = Operation; impl RichTextOperation { - pub fn contain_attribute(&self, attribute: &RichTextAttribute) -> bool { + pub fn contain_attribute(&self, attribute: &TextAttribute) -> bool { self.get_attributes().contains_key(&attribute.key) } } #[derive(Debug, Clone, Eq, PartialEq)] -pub struct RichTextAttributes { - pub(crate) inner: HashMap, +pub struct TextAttributes { + pub(crate) inner: HashMap, } -impl std::default::Default for RichTextAttributes { +impl std::default::Default for TextAttributes { fn default() -> Self { Self { inner: HashMap::with_capacity(0), @@ -30,40 +30,40 @@ impl std::default::Default for RichTextAttributes { } } -impl fmt::Display for RichTextAttributes { +impl fmt::Display for TextAttributes { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_fmt(format_args!("{:?}", self.inner)) } } #[inline(always)] -pub fn plain_attributes() -> RichTextAttributes { - RichTextAttributes::default() +pub fn plain_attributes() -> TextAttributes { + TextAttributes::default() } -impl RichTextAttributes { +impl TextAttributes { pub fn new() -> Self { - RichTextAttributes { inner: HashMap::new() } + TextAttributes { inner: HashMap::new() } } pub fn is_empty(&self) -> bool { self.inner.is_empty() } - pub fn add(&mut self, attribute: RichTextAttribute) { - let RichTextAttribute { key, value, scope: _ } = attribute; + pub fn add(&mut self, attribute: TextAttribute) { + let TextAttribute { key, value, scope: _ } = attribute; self.inner.insert(key, value); } - pub fn insert(&mut self, key: RichTextAttributeKey, value: RichTextAttributeValue) { + pub fn insert(&mut self, key: TextAttributeKey, value: TextAttributeValue) { self.inner.insert(key, value); } - pub fn delete(&mut self, key: &RichTextAttributeKey) { - self.inner.insert(key.clone(), RichTextAttributeValue(None)); + pub fn delete(&mut self, key: &TextAttributeKey) { + self.inner.insert(key.clone(), TextAttributeValue(None)); } - pub fn mark_all_as_removed_except(&mut self, attribute: Option) { + pub fn mark_all_as_removed_except(&mut self, attribute: Option) { match attribute { None => { self.inner.iter_mut().for_each(|(_k, v)| v.0 = None); @@ -78,7 +78,7 @@ impl RichTextAttributes { } } - pub fn remove(&mut self, key: RichTextAttributeKey) { + pub fn remove(&mut self, key: TextAttributeKey) { self.inner.retain(|k, _| k != &key); } @@ -95,7 +95,7 @@ impl RichTextAttributes { // Update inner by constructing new attributes from the other if it's // not None and replace the key/value with self key/value. - pub fn merge(&mut self, other: Option) { + pub fn merge(&mut self, other: Option) { if other.is_none() { return; } @@ -108,7 +108,7 @@ impl RichTextAttributes { } } -impl Attributes for RichTextAttributes { +impl Attributes for TextAttributes { fn is_empty(&self) -> bool { self.inner.is_empty() } @@ -122,7 +122,7 @@ impl Attributes for RichTextAttributes { } } -impl OperationTransform for RichTextAttributes { +impl OperationTransform for TextAttributes { fn compose(&self, other: &Self) -> Result where Self: Sized, @@ -136,29 +136,25 @@ impl OperationTransform for RichTextAttributes { where Self: Sized, { - let a = self - .iter() - .fold(RichTextAttributes::new(), |mut new_attributes, (k, v)| { - if !other.contains_key(k) { - new_attributes.insert(k.clone(), v.clone()); - } - new_attributes - }); + let a = self.iter().fold(TextAttributes::new(), |mut new_attributes, (k, v)| { + if !other.contains_key(k) { + new_attributes.insert(k.clone(), v.clone()); + } + new_attributes + }); - let b = other - .iter() - .fold(RichTextAttributes::new(), |mut new_attributes, (k, v)| { - if !self.contains_key(k) { - new_attributes.insert(k.clone(), v.clone()); - } - new_attributes - }); + let b = other.iter().fold(TextAttributes::new(), |mut new_attributes, (k, v)| { + if !self.contains_key(k) { + new_attributes.insert(k.clone(), v.clone()); + } + new_attributes + }); Ok((a, b)) } fn invert(&self, other: &Self) -> Self { - let base_inverted = other.iter().fold(RichTextAttributes::new(), |mut attributes, (k, v)| { + let base_inverted = other.iter().fold(TextAttributes::new(), |mut attributes, (k, v)| { if other.get(k) != self.get(k) && self.contains_key(k) { attributes.insert(k.clone(), v.clone()); } @@ -176,34 +172,34 @@ impl OperationTransform for RichTextAttributes { } } -impl std::ops::Deref for RichTextAttributes { - type Target = HashMap; +impl std::ops::Deref for TextAttributes { + type Target = HashMap; fn deref(&self) -> &Self::Target { &self.inner } } -impl std::ops::DerefMut for RichTextAttributes { +impl std::ops::DerefMut for TextAttributes { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner } } -pub fn attributes_except_header(op: &RichTextOperation) -> RichTextAttributes { +pub fn attributes_except_header(op: &RichTextOperation) -> TextAttributes { let mut attributes = op.get_attributes(); - attributes.remove(RichTextAttributeKey::Header); + attributes.remove(TextAttributeKey::Header); attributes } #[derive(Debug, Clone)] -pub struct RichTextAttribute { - pub key: RichTextAttributeKey, - pub value: RichTextAttributeValue, +pub struct TextAttribute { + pub key: TextAttributeKey, + pub value: TextAttributeValue, pub scope: AttributeScope, } -impl RichTextAttribute { +impl TextAttribute { // inline inline_attribute!(Bold, bool); inline_attribute!(Italic, bool); @@ -245,16 +241,16 @@ impl RichTextAttribute { } } -impl fmt::Display for RichTextAttribute { +impl fmt::Display for TextAttribute { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { let s = format!("{:?}:{:?} {:?}", self.key, self.value.0, self.scope); f.write_str(&s) } } -impl std::convert::From for RichTextAttributes { - fn from(attr: RichTextAttribute) -> Self { - let mut attributes = RichTextAttributes::new(); +impl std::convert::From for TextAttributes { + fn from(attr: TextAttribute) -> Self { + let mut attributes = TextAttributes::new(); attributes.add(attr); attributes } @@ -263,7 +259,7 @@ impl std::convert::From for RichTextAttributes { #[derive(Clone, Debug, Display, Hash, Eq, PartialEq, serde::Serialize, serde::Deserialize)] // serde.rs/variant-attrs.html // #[serde(rename_all = "snake_case")] -pub enum RichTextAttributeKey { +pub enum TextAttributeKey { #[serde(rename = "bold")] Bold, #[serde(rename = "italic")] @@ -304,90 +300,90 @@ pub enum RichTextAttributeKey { // pub trait AttributeValueData<'a>: Serialize + Deserialize<'a> {} #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct RichTextAttributeValue(pub Option); +pub struct TextAttributeValue(pub Option); -impl std::convert::From<&usize> for RichTextAttributeValue { +impl std::convert::From<&usize> for TextAttributeValue { fn from(val: &usize) -> Self { - RichTextAttributeValue::from(*val) + TextAttributeValue::from(*val) } } -impl std::convert::From for RichTextAttributeValue { +impl std::convert::From for TextAttributeValue { fn from(val: usize) -> Self { if val > 0_usize { - RichTextAttributeValue(Some(format!("{}", val))) + TextAttributeValue(Some(format!("{}", val))) } else { - RichTextAttributeValue(None) + TextAttributeValue(None) } } } -impl std::convert::From<&str> for RichTextAttributeValue { +impl std::convert::From<&str> for TextAttributeValue { fn from(val: &str) -> Self { val.to_owned().into() } } -impl std::convert::From for RichTextAttributeValue { +impl std::convert::From for TextAttributeValue { fn from(val: String) -> Self { if val.is_empty() { - RichTextAttributeValue(None) + TextAttributeValue(None) } else { - RichTextAttributeValue(Some(val)) + TextAttributeValue(Some(val)) } } } -impl std::convert::From<&bool> for RichTextAttributeValue { +impl std::convert::From<&bool> for TextAttributeValue { fn from(val: &bool) -> Self { - RichTextAttributeValue::from(*val) + TextAttributeValue::from(*val) } } -impl std::convert::From for RichTextAttributeValue { +impl std::convert::From for TextAttributeValue { fn from(val: bool) -> Self { let val = match val { true => Some("true".to_owned()), false => None, }; - RichTextAttributeValue(val) + TextAttributeValue(val) } } -pub fn is_block_except_header(k: &RichTextAttributeKey) -> bool { - if k == &RichTextAttributeKey::Header { +pub fn is_block_except_header(k: &TextAttributeKey) -> bool { + if k == &TextAttributeKey::Header { return false; } BLOCK_KEYS.contains(k) } -pub fn is_block(k: &RichTextAttributeKey) -> bool { +pub fn is_block(k: &TextAttributeKey) -> bool { BLOCK_KEYS.contains(k) } lazy_static! { - static ref BLOCK_KEYS: HashSet = HashSet::from_iter(vec![ - RichTextAttributeKey::Header, - RichTextAttributeKey::Indent, - RichTextAttributeKey::Align, - RichTextAttributeKey::CodeBlock, - RichTextAttributeKey::List, - RichTextAttributeKey::BlockQuote, + static ref BLOCK_KEYS: HashSet = HashSet::from_iter(vec![ + TextAttributeKey::Header, + TextAttributeKey::Indent, + TextAttributeKey::Align, + TextAttributeKey::CodeBlock, + TextAttributeKey::List, + TextAttributeKey::BlockQuote, ]); - static ref INLINE_KEYS: HashSet = HashSet::from_iter(vec![ - RichTextAttributeKey::Bold, - RichTextAttributeKey::Italic, - RichTextAttributeKey::Underline, - RichTextAttributeKey::StrikeThrough, - RichTextAttributeKey::Link, - RichTextAttributeKey::Color, - RichTextAttributeKey::Font, - RichTextAttributeKey::Size, - RichTextAttributeKey::Background, - RichTextAttributeKey::InlineCode, + static ref INLINE_KEYS: HashSet = HashSet::from_iter(vec![ + TextAttributeKey::Bold, + TextAttributeKey::Italic, + TextAttributeKey::Underline, + TextAttributeKey::StrikeThrough, + TextAttributeKey::Link, + TextAttributeKey::Color, + TextAttributeKey::Font, + TextAttributeKey::Size, + TextAttributeKey::Background, + TextAttributeKey::InlineCode, ]); - static ref INGORE_KEYS: HashSet = - HashSet::from_iter(vec![RichTextAttributeKey::Width, RichTextAttributeKey::Height,]); + static ref INGORE_KEYS: HashSet = + HashSet::from_iter(vec![TextAttributeKey::Width, TextAttributeKey::Height,]); } #[derive(Debug, PartialEq, Eq, Clone)] diff --git a/shared-lib/lib-ot/src/rich_text/attributes_serde.rs b/shared-lib/lib-ot/src/rich_text/attributes_serde.rs index 19ffb5a416..42c8c73834 100644 --- a/shared-lib/lib-ot/src/rich_text/attributes_serde.rs +++ b/shared-lib/lib-ot/src/rich_text/attributes_serde.rs @@ -1,5 +1,5 @@ #[rustfmt::skip] -use crate::rich_text::{RichTextAttribute, RichTextAttributeKey, RichTextAttributes, RichTextAttributeValue}; +use crate::rich_text::{TextAttribute, TextAttributeKey, TextAttributes, TextAttributeValue}; use serde::{ de, de::{MapAccess, Visitor}, @@ -8,7 +8,7 @@ use serde::{ }; use std::fmt; -impl Serialize for RichTextAttribute { +impl Serialize for TextAttribute { fn serialize(&self, serializer: S) -> Result<::Ok, ::Error> where S: Serializer, @@ -19,7 +19,7 @@ impl Serialize for RichTextAttribute { } } -impl Serialize for RichTextAttributes { +impl Serialize for TextAttributes { fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -36,43 +36,39 @@ impl Serialize for RichTextAttributes { } } -fn serial_attribute( - map_serializer: &mut S, - key: &RichTextAttributeKey, - value: &RichTextAttributeValue, -) -> Result<(), E> +fn serial_attribute(map_serializer: &mut S, key: &TextAttributeKey, value: &TextAttributeValue) -> Result<(), E> where S: SerializeMap, E: From<::Error>, { if let Some(v) = &value.0 { match key { - RichTextAttributeKey::Bold - | RichTextAttributeKey::Italic - | RichTextAttributeKey::Underline - | RichTextAttributeKey::StrikeThrough - | RichTextAttributeKey::CodeBlock - | RichTextAttributeKey::InlineCode - | RichTextAttributeKey::BlockQuote => match &v.parse::() { + TextAttributeKey::Bold + | TextAttributeKey::Italic + | TextAttributeKey::Underline + | TextAttributeKey::StrikeThrough + | TextAttributeKey::CodeBlock + | TextAttributeKey::InlineCode + | TextAttributeKey::BlockQuote => match &v.parse::() { Ok(value) => map_serializer.serialize_entry(&key, value)?, Err(e) => log::error!("Serial {:?} failed. {:?}", &key, e), }, - RichTextAttributeKey::Font - | RichTextAttributeKey::Size - | RichTextAttributeKey::Header - | RichTextAttributeKey::Indent - | RichTextAttributeKey::Width - | RichTextAttributeKey::Height => match &v.parse::() { + TextAttributeKey::Font + | TextAttributeKey::Size + | TextAttributeKey::Header + | TextAttributeKey::Indent + | TextAttributeKey::Width + | TextAttributeKey::Height => match &v.parse::() { Ok(value) => map_serializer.serialize_entry(&key, value)?, Err(e) => log::error!("Serial {:?} failed. {:?}", &key, e), }, - RichTextAttributeKey::Link - | RichTextAttributeKey::Color - | RichTextAttributeKey::Background - | RichTextAttributeKey::Align - | RichTextAttributeKey::List => { + TextAttributeKey::Link + | TextAttributeKey::Color + | TextAttributeKey::Background + | TextAttributeKey::Align + | TextAttributeKey::List => { map_serializer.serialize_entry(&key, v)?; } } @@ -82,14 +78,14 @@ where Ok(()) } -impl<'de> Deserialize<'de> for RichTextAttributes { - fn deserialize(deserializer: D) -> Result +impl<'de> Deserialize<'de> for TextAttributes { + fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { struct AttributesVisitor; impl<'de> Visitor<'de> for AttributesVisitor { - type Value = RichTextAttributes; + type Value = TextAttributes; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("Expect map") } @@ -98,9 +94,9 @@ impl<'de> Deserialize<'de> for RichTextAttributes { where A: MapAccess<'de>, { - let mut attributes = RichTextAttributes::new(); - while let Some(key) = map.next_key::()? { - let value = map.next_value::()?; + let mut attributes = TextAttributes::new(); + while let Some(key) = map.next_key::()? { + let value = map.next_value::()?; attributes.insert(key, value); } @@ -111,7 +107,7 @@ impl<'de> Deserialize<'de> for RichTextAttributes { } } -impl Serialize for RichTextAttributeValue { +impl Serialize for TextAttributeValue { fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -123,14 +119,14 @@ impl Serialize for RichTextAttributeValue { } } -impl<'de> Deserialize<'de> for RichTextAttributeValue { - fn deserialize(deserializer: D) -> Result +impl<'de> Deserialize<'de> for TextAttributeValue { + fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { struct AttributeValueVisitor; impl<'de> Visitor<'de> for AttributeValueVisitor { - type Value = RichTextAttributeValue; + type Value = TextAttributeValue; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("bool, usize or string") } @@ -145,56 +141,56 @@ impl<'de> Deserialize<'de> for RichTextAttributeValue { where E: de::Error, { - Ok(RichTextAttributeValue(Some(format!("{}", value)))) + Ok(TextAttributeValue(Some(format!("{}", value)))) } fn visit_i16(self, value: i16) -> Result where E: de::Error, { - Ok(RichTextAttributeValue(Some(format!("{}", value)))) + Ok(TextAttributeValue(Some(format!("{}", value)))) } fn visit_i32(self, value: i32) -> Result where E: de::Error, { - Ok(RichTextAttributeValue(Some(format!("{}", value)))) + Ok(TextAttributeValue(Some(format!("{}", value)))) } fn visit_i64(self, value: i64) -> Result where E: de::Error, { - Ok(RichTextAttributeValue(Some(format!("{}", value)))) + Ok(TextAttributeValue(Some(format!("{}", value)))) } fn visit_u8(self, value: u8) -> Result where E: de::Error, { - Ok(RichTextAttributeValue(Some(format!("{}", value)))) + Ok(TextAttributeValue(Some(format!("{}", value)))) } fn visit_u16(self, value: u16) -> Result where E: de::Error, { - Ok(RichTextAttributeValue(Some(format!("{}", value)))) + Ok(TextAttributeValue(Some(format!("{}", value)))) } fn visit_u32(self, value: u32) -> Result where E: de::Error, { - Ok(RichTextAttributeValue(Some(format!("{}", value)))) + Ok(TextAttributeValue(Some(format!("{}", value)))) } fn visit_u64(self, value: u64) -> Result where E: de::Error, { - Ok(RichTextAttributeValue(Some(format!("{}", value)))) + Ok(TextAttributeValue(Some(format!("{}", value)))) } fn visit_str(self, s: &str) -> Result @@ -208,7 +204,7 @@ impl<'de> Deserialize<'de> for RichTextAttributeValue { where E: de::Error, { - Ok(RichTextAttributeValue(None)) + Ok(TextAttributeValue(None)) } fn visit_unit(self) -> Result @@ -216,7 +212,7 @@ impl<'de> Deserialize<'de> for RichTextAttributeValue { E: de::Error, { // the value that contains null will be processed here. - Ok(RichTextAttributeValue(None)) + Ok(TextAttributeValue(None)) } fn visit_map(self, map: A) -> Result @@ -225,7 +221,7 @@ impl<'de> Deserialize<'de> for RichTextAttributeValue { { // https://github.com/serde-rs/json/issues/505 let mut map = map; - let value = map.next_value::()?; + let value = map.next_value::()?; Ok(value) } } diff --git a/shared-lib/lib-ot/src/rich_text/builder.rs b/shared-lib/lib-ot/src/rich_text/builder.rs index 84f3f09cfe..cc0a4e4370 100644 --- a/shared-lib/lib-ot/src/rich_text/builder.rs +++ b/shared-lib/lib-ot/src/rich_text/builder.rs @@ -1,15 +1,15 @@ #![allow(non_snake_case)] #![allow(clippy::derivable_impls)] -use crate::rich_text::{RichTextAttribute, RichTextAttributes}; +use crate::rich_text::{TextAttribute, TextAttributes}; pub struct AttributeBuilder { - inner: RichTextAttributes, + inner: TextAttributes, } impl std::default::Default for AttributeBuilder { fn default() -> Self { Self { - inner: RichTextAttributes::default(), + inner: TextAttributes::default(), } } } @@ -19,12 +19,12 @@ impl AttributeBuilder { AttributeBuilder::default() } - pub fn add_attr(mut self, attribute: RichTextAttribute) -> Self { + pub fn add_attr(mut self, attribute: TextAttribute) -> Self { self.inner.add(attribute); self } - pub fn build(self) -> RichTextAttributes { + pub fn build(self) -> TextAttributes { self.inner } } diff --git a/shared-lib/lib-ot/src/rich_text/delta.rs b/shared-lib/lib-ot/src/rich_text/delta.rs index 3a60cf7b02..f00d29e72a 100644 --- a/shared-lib/lib-ot/src/rich_text/delta.rs +++ b/shared-lib/lib-ot/src/rich_text/delta.rs @@ -1,5 +1,5 @@ use crate::core::{Delta, DeltaBuilder}; -use crate::rich_text::RichTextAttributes; +use crate::rich_text::TextAttributes; -pub type RichTextDelta = Delta; -pub type RichTextDeltaBuilder = DeltaBuilder; +pub type RichTextDelta = Delta; +pub type RichTextDeltaBuilder = DeltaBuilder; diff --git a/shared-lib/lib-ot/src/rich_text/macros.rs b/shared-lib/lib-ot/src/rich_text/macros.rs index 28fe903183..c8c396427d 100644 --- a/shared-lib/lib-ot/src/rich_text/macros.rs +++ b/shared-lib/lib-ot/src/rich_text/macros.rs @@ -6,7 +6,7 @@ macro_rules! inline_attribute { ) => { pub fn $key(value: $value) -> Self { Self { - key: RichTextAttributeKey::$key, + key: TextAttributeKey::$key, value: value.into(), scope: AttributeScope::Inline, } @@ -22,7 +22,7 @@ macro_rules! block_attribute { ) => { pub fn $key(value: $value) -> Self { Self { - key: RichTextAttributeKey::$key, + key: TextAttributeKey::$key, value: value.into(), scope: AttributeScope::Block, } @@ -41,7 +41,7 @@ macro_rules! list_attribute { true => $value, false => "", }; - RichTextAttribute::List(value) + TextAttribute::List(value) } }; } @@ -54,7 +54,7 @@ macro_rules! ignore_attribute { ) => { pub fn $key(value: $value) -> Self { Self { - key: RichTextAttributeKey::$key, + key: TextAttributeKey::$key, value: value.into(), scope: AttributeScope::Ignore, } diff --git a/shared-lib/lib-ot/tests/node/script.rs b/shared-lib/lib-ot/tests/node/script.rs index 34daca8d7c..c263a1330c 100644 --- a/shared-lib/lib-ot/tests/node/script.rs +++ b/shared-lib/lib-ot/tests/node/script.rs @@ -1,21 +1,21 @@ -use lib_ot::core::{DocumentTree, NodeAttributes, NodeSubTree, Path, TransactionBuilder}; +use lib_ot::core::{Node, NodeAttributes, NodeTree, Path, TransactionBuilder}; pub enum NodeScript { - InsertNode { path: Path, node: NodeSubTree }, + InsertNode { path: Path, node: Node }, InsertAttributes { path: Path, attributes: NodeAttributes }, DeleteNode { path: Path }, AssertNumberOfChildrenAtPath { path: Option, len: usize }, - AssertNode { path: Path, expected: Option }, + AssertNode { path: Path, expected: Option }, } pub struct NodeTest { - node_tree: DocumentTree, + node_tree: NodeTree, } impl NodeTest { pub fn new() -> Self { Self { - node_tree: DocumentTree::new(), + node_tree: NodeTree::new(), } } @@ -36,7 +36,7 @@ impl NodeTest { } NodeScript::InsertAttributes { path, attributes } => { let transaction = TransactionBuilder::new(&self.node_tree) - .update_attributes_at_path(&path, attributes.to_inner()) + .update_attributes_at_path(&path, attributes) .finalize(); self.node_tree.apply(transaction).unwrap(); } @@ -53,7 +53,7 @@ impl NodeTest { None => assert!(node_id.is_none()), Some(node_id) => { let node_data = self.node_tree.get_node_data(node_id).cloned(); - assert_eq!(node_data, expected.and_then(|e| Some(e.to_node_data()))); + assert_eq!(node_data, expected.and_then(|e| Some(e.into()))); } } } diff --git a/shared-lib/lib-ot/tests/node/test.rs b/shared-lib/lib-ot/tests/node/test.rs index d299b08714..aa15ff76a5 100644 --- a/shared-lib/lib-ot/tests/node/test.rs +++ b/shared-lib/lib-ot/tests/node/test.rs @@ -1,11 +1,11 @@ use crate::node::script::NodeScript::*; use crate::node::script::NodeTest; -use lib_ot::core::{NodeAttributes, NodeSubTree, Path}; +use lib_ot::core::{Node, NodeAttributes, Path}; #[test] fn node_insert_test() { let mut test = NodeTest::new(); - let inserted_node = NodeSubTree::new("text"); + let inserted_node = Node::new("text"); let path: Path = 0.into(); let scripts = vec![ InsertNode { @@ -23,11 +23,11 @@ fn node_insert_test() { #[test] fn node_insert_node_with_children_test() { let mut test = NodeTest::new(); - let inserted_node = NodeSubTree { + let inserted_node = Node { note_type: "text".into(), attributes: NodeAttributes::new(), delta: None, - children: vec![NodeSubTree::new("image")], + children: vec![Node::new("image")], }; let path: Path = 0.into(); let scripts = vec![ @@ -47,13 +47,13 @@ fn node_insert_node_with_children_test() { fn node_insert_multi_nodes_test() { let mut test = NodeTest::new(); let path_1: Path = 0.into(); - let node_1 = NodeSubTree::new("text_1"); + let node_1 = Node::new("text_1"); let path_2: Path = 1.into(); - let node_2 = NodeSubTree::new("text_2"); + let node_2 = Node::new("text_2"); let path_3: Path = 2.into(); - let node_3 = NodeSubTree::new("text_3"); + let node_3 = Node::new("text_3"); let scripts = vec![ InsertNode { @@ -88,14 +88,14 @@ fn node_insert_multi_nodes_test() { fn node_insert_node_in_ordered_nodes_test() { let mut test = NodeTest::new(); let path_1: Path = 0.into(); - let node_1 = NodeSubTree::new("text_1"); + let node_1 = Node::new("text_1"); let path_2: Path = 1.into(); - let node_2_1 = NodeSubTree::new("text_2_1"); - let node_2_2 = NodeSubTree::new("text_2_2"); + let node_2_1 = Node::new("text_2_1"); + let node_2_2 = Node::new("text_2_2"); let path_3: Path = 2.into(); - let node_3 = NodeSubTree::new("text_3"); + let node_3 = Node::new("text_3"); let path_4: Path = 3.into(); @@ -143,11 +143,9 @@ fn node_insert_node_in_ordered_nodes_test() { fn node_insert_with_attributes_test() { let mut test = NodeTest::new(); let path: Path = 0.into(); - let mut inserted_node = NodeSubTree::new("text"); - inserted_node.attributes.insert("bold".to_string(), Some("true".into())); - inserted_node - .attributes - .insert("underline".to_string(), Some("true".into())); + let mut inserted_node = Node::new("text"); + inserted_node.attributes.insert("bold", true); + inserted_node.attributes.insert("underline", true); let scripts = vec![ InsertNode { @@ -169,7 +167,7 @@ fn node_insert_with_attributes_test() { #[test] fn node_delete_test() { let mut test = NodeTest::new(); - let inserted_node = NodeSubTree::new("text"); + let inserted_node = Node::new("text"); let path: Path = 0.into(); let scripts = vec![