mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
Merge pull request #748 from AppFlowy-IO/feat/lib_ot_documentation
Feat/lib ot documentation
This commit is contained in:
commit
3385c2f7f8
@ -10,7 +10,7 @@ use flowy_sync::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
use lib_infra::future::{BoxResultFuture, FutureResult};
|
use lib_infra::future::{BoxResultFuture, FutureResult};
|
||||||
use lib_ot::core::{OperationTransformable, PhantomAttributes, PlainTextDelta};
|
use lib_ot::core::{OperationTransform, PhantomAttributes, PlainTextDelta};
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use std::{sync::Arc, time::Duration};
|
use std::{sync::Arc, time::Duration};
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ use flowy_sync::{
|
|||||||
};
|
};
|
||||||
use futures::stream::StreamExt;
|
use futures::stream::StreamExt;
|
||||||
use lib_ot::{
|
use lib_ot::{
|
||||||
core::{Interval, OperationTransformable},
|
core::{Interval, OperationTransform},
|
||||||
rich_text::{RichTextAttribute, RichTextAttributes, RichTextDelta},
|
rich_text::{RichTextAttribute, RichTextAttributes, RichTextDelta},
|
||||||
};
|
};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#![cfg_attr(rustfmt, rustfmt::skip)]
|
#![cfg_attr(rustfmt, rustfmt::skip)]
|
||||||
use crate::editor::{TestBuilder, TestOp::*};
|
use crate::editor::{TestBuilder, TestOp::*};
|
||||||
use flowy_sync::client_document::{NewlineDoc, PlainDoc};
|
use flowy_sync::client_document::{NewlineDoc, PlainDoc};
|
||||||
use lib_ot::core::{Interval, OperationTransformable, NEW_LINE, WHITESPACE, FlowyStr};
|
use lib_ot::core::{Interval, OperationTransform, NEW_LINE, WHITESPACE, OTString};
|
||||||
use unicode_segmentation::UnicodeSegmentation;
|
use unicode_segmentation::UnicodeSegmentation;
|
||||||
use lib_ot::rich_text::RichTextDelta;
|
use lib_ot::rich_text::RichTextDelta;
|
||||||
|
|
||||||
@ -723,8 +723,8 @@ fn attributes_preserve_header_format_on_merge() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn attributes_format_emoji() {
|
fn attributes_format_emoji() {
|
||||||
let emoji_s = "👋 ";
|
let emoji_s = "👋 ";
|
||||||
let s: FlowyStr = emoji_s.into();
|
let s: OTString = emoji_s.into();
|
||||||
let len = s.utf16_size();
|
let len = s.utf16_len();
|
||||||
assert_eq!(3, len);
|
assert_eq!(3, len);
|
||||||
assert_eq!(2, s.graphemes(true).count());
|
assert_eq!(2, s.graphemes(true).count());
|
||||||
|
|
||||||
|
@ -300,9 +300,9 @@ impl Rng {
|
|||||||
|
|
||||||
pub fn gen_delta(&mut self, s: &str) -> RichTextDelta {
|
pub fn gen_delta(&mut self, s: &str) -> RichTextDelta {
|
||||||
let mut delta = RichTextDelta::default();
|
let mut delta = RichTextDelta::default();
|
||||||
let s = FlowyStr::from(s);
|
let s = OTString::from(s);
|
||||||
loop {
|
loop {
|
||||||
let left = s.utf16_size() - delta.utf16_base_len;
|
let left = s.utf16_len() - delta.utf16_base_len;
|
||||||
if left == 0 {
|
if left == 0 {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#![allow(clippy::all)]
|
#![allow(clippy::all)]
|
||||||
use crate::editor::{Rng, TestBuilder, TestOp::*};
|
use crate::editor::{Rng, TestBuilder, TestOp::*};
|
||||||
use flowy_sync::client_document::{NewlineDoc, PlainDoc};
|
use flowy_sync::client_document::{NewlineDoc, PlainDoc};
|
||||||
|
use lib_ot::rich_text::RichTextDeltaBuilder;
|
||||||
use lib_ot::{
|
use lib_ot::{
|
||||||
core::Interval,
|
core::Interval,
|
||||||
core::*,
|
core::*,
|
||||||
@ -39,12 +40,8 @@ fn attributes_insert_text_at_middle() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn delta_get_ops_in_interval_1() {
|
fn delta_get_ops_in_interval_1() {
|
||||||
let mut delta = RichTextDelta::default();
|
let operations = OperationsBuilder::new().insert("123").insert("4").build();
|
||||||
let insert_a = OperationBuilder::insert("123").build();
|
let delta = RichTextDeltaBuilder::from_operations(operations);
|
||||||
let insert_b = OperationBuilder::insert("4").build();
|
|
||||||
|
|
||||||
delta.add(insert_a.clone());
|
|
||||||
delta.add(insert_b.clone());
|
|
||||||
|
|
||||||
let mut iterator = DeltaIterator::from_interval(&delta, Interval::new(0, 4));
|
let mut iterator = DeltaIterator::from_interval(&delta, Interval::new(0, 4));
|
||||||
assert_eq!(iterator.ops(), delta.ops);
|
assert_eq!(iterator.ops(), delta.ops);
|
||||||
@ -53,10 +50,10 @@ fn delta_get_ops_in_interval_1() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn delta_get_ops_in_interval_2() {
|
fn delta_get_ops_in_interval_2() {
|
||||||
let mut delta = RichTextDelta::default();
|
let mut delta = RichTextDelta::default();
|
||||||
let insert_a = OperationBuilder::insert("123").build();
|
let insert_a = Operation::insert("123");
|
||||||
let insert_b = OperationBuilder::insert("4").build();
|
let insert_b = Operation::insert("4");
|
||||||
let insert_c = OperationBuilder::insert("5").build();
|
let insert_c = Operation::insert("5");
|
||||||
let retain_a = OperationBuilder::retain(3).build();
|
let retain_a = Operation::retain(3);
|
||||||
|
|
||||||
delta.add(insert_a.clone());
|
delta.add(insert_a.clone());
|
||||||
delta.add(retain_a.clone());
|
delta.add(retain_a.clone());
|
||||||
@ -65,12 +62,12 @@ fn delta_get_ops_in_interval_2() {
|
|||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DeltaIterator::from_interval(&delta, Interval::new(0, 2)).ops(),
|
DeltaIterator::from_interval(&delta, Interval::new(0, 2)).ops(),
|
||||||
vec![OperationBuilder::insert("12").build()]
|
vec![Operation::insert("12")]
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DeltaIterator::from_interval(&delta, Interval::new(1, 3)).ops(),
|
DeltaIterator::from_interval(&delta, Interval::new(1, 3)).ops(),
|
||||||
vec![OperationBuilder::insert("23").build()]
|
vec![Operation::insert("23")]
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -80,7 +77,7 @@ fn delta_get_ops_in_interval_2() {
|
|||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DeltaIterator::from_interval(&delta, Interval::new(0, 4)).ops(),
|
DeltaIterator::from_interval(&delta, Interval::new(0, 4)).ops(),
|
||||||
vec![insert_a.clone(), OperationBuilder::retain(1).build()]
|
vec![insert_a.clone(), Operation::retain(1)]
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -97,20 +94,20 @@ fn delta_get_ops_in_interval_2() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn delta_get_ops_in_interval_3() {
|
fn delta_get_ops_in_interval_3() {
|
||||||
let mut delta = RichTextDelta::default();
|
let mut delta = RichTextDelta::default();
|
||||||
let insert_a = OperationBuilder::insert("123456").build();
|
let insert_a = Operation::insert("123456");
|
||||||
delta.add(insert_a.clone());
|
delta.add(insert_a.clone());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DeltaIterator::from_interval(&delta, Interval::new(3, 5)).ops(),
|
DeltaIterator::from_interval(&delta, Interval::new(3, 5)).ops(),
|
||||||
vec![OperationBuilder::insert("45").build()]
|
vec![Operation::insert("45")]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn delta_get_ops_in_interval_4() {
|
fn delta_get_ops_in_interval_4() {
|
||||||
let mut delta = RichTextDelta::default();
|
let mut delta = RichTextDelta::default();
|
||||||
let insert_a = OperationBuilder::insert("12").build();
|
let insert_a = Operation::insert("12");
|
||||||
let insert_b = OperationBuilder::insert("34").build();
|
let insert_b = Operation::insert("34");
|
||||||
let insert_c = OperationBuilder::insert("56").build();
|
let insert_c = Operation::insert("56");
|
||||||
|
|
||||||
delta.ops.push(insert_a.clone());
|
delta.ops.push(insert_a.clone());
|
||||||
delta.ops.push(insert_b.clone());
|
delta.ops.push(insert_b.clone());
|
||||||
@ -131,73 +128,64 @@ fn delta_get_ops_in_interval_4() {
|
|||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DeltaIterator::from_interval(&delta, Interval::new(2, 5)).ops(),
|
DeltaIterator::from_interval(&delta, Interval::new(2, 5)).ops(),
|
||||||
vec![
|
vec![Operation::insert("34"), Operation::insert("5")]
|
||||||
OperationBuilder::insert("34").build(),
|
|
||||||
OperationBuilder::insert("5").build()
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn delta_get_ops_in_interval_5() {
|
fn delta_get_ops_in_interval_5() {
|
||||||
let mut delta = RichTextDelta::default();
|
let mut delta = RichTextDelta::default();
|
||||||
let insert_a = OperationBuilder::insert("123456").build();
|
let insert_a = Operation::insert("123456");
|
||||||
let insert_b = OperationBuilder::insert("789").build();
|
let insert_b = Operation::insert("789");
|
||||||
delta.ops.push(insert_a.clone());
|
delta.ops.push(insert_a.clone());
|
||||||
delta.ops.push(insert_b.clone());
|
delta.ops.push(insert_b.clone());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DeltaIterator::from_interval(&delta, Interval::new(4, 8)).ops(),
|
DeltaIterator::from_interval(&delta, Interval::new(4, 8)).ops(),
|
||||||
vec![
|
vec![Operation::insert("56"), Operation::insert("78")]
|
||||||
OperationBuilder::insert("56").build(),
|
|
||||||
OperationBuilder::insert("78").build()
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// assert_eq!(
|
// assert_eq!(
|
||||||
// DeltaIter::from_interval(&delta, Interval::new(8, 9)).ops(),
|
// DeltaIter::from_interval(&delta, Interval::new(8, 9)).ops(),
|
||||||
// vec![Builder::insert("9").build()]
|
// vec![Builder::insert("9")]
|
||||||
// );
|
// );
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn delta_get_ops_in_interval_6() {
|
fn delta_get_ops_in_interval_6() {
|
||||||
let mut delta = RichTextDelta::default();
|
let mut delta = RichTextDelta::default();
|
||||||
let insert_a = OperationBuilder::insert("12345678").build();
|
let insert_a = Operation::insert("12345678");
|
||||||
delta.add(insert_a.clone());
|
delta.add(insert_a.clone());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
DeltaIterator::from_interval(&delta, Interval::new(4, 6)).ops(),
|
DeltaIterator::from_interval(&delta, Interval::new(4, 6)).ops(),
|
||||||
vec![OperationBuilder::insert("56").build()]
|
vec![Operation::insert("56")]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn delta_get_ops_in_interval_7() {
|
fn delta_get_ops_in_interval_7() {
|
||||||
let mut delta = RichTextDelta::default();
|
let mut delta = RichTextDelta::default();
|
||||||
let insert_a = OperationBuilder::insert("12345").build();
|
let insert_a = Operation::insert("12345");
|
||||||
let retain_a = OperationBuilder::retain(3).build();
|
let retain_a = Operation::retain(3);
|
||||||
|
|
||||||
delta.add(insert_a.clone());
|
delta.add(insert_a.clone());
|
||||||
delta.add(retain_a.clone());
|
delta.add(retain_a.clone());
|
||||||
|
|
||||||
let mut iter_1 = DeltaIterator::from_offset(&delta, 2);
|
let mut iter_1 = DeltaIterator::from_offset(&delta, 2);
|
||||||
assert_eq!(iter_1.next_op().unwrap(), OperationBuilder::insert("345").build());
|
assert_eq!(iter_1.next_op().unwrap(), Operation::insert("345"));
|
||||||
assert_eq!(iter_1.next_op().unwrap(), OperationBuilder::retain(3).build());
|
assert_eq!(iter_1.next_op().unwrap(), Operation::retain(3));
|
||||||
|
|
||||||
let mut iter_2 = DeltaIterator::new(&delta);
|
let mut iter_2 = DeltaIterator::new(&delta);
|
||||||
assert_eq!(
|
assert_eq!(iter_2.next_op_with_len(2).unwrap(), Operation::insert("12"));
|
||||||
iter_2.next_op_with_len(2).unwrap(),
|
assert_eq!(iter_2.next_op().unwrap(), Operation::insert("345"));
|
||||||
OperationBuilder::insert("12").build()
|
|
||||||
);
|
|
||||||
assert_eq!(iter_2.next_op().unwrap(), OperationBuilder::insert("345").build());
|
|
||||||
|
|
||||||
assert_eq!(iter_2.next_op().unwrap(), OperationBuilder::retain(3).build());
|
assert_eq!(iter_2.next_op().unwrap(), Operation::retain(3));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn delta_op_seek() {
|
fn delta_op_seek() {
|
||||||
let mut delta = RichTextDelta::default();
|
let mut delta = RichTextDelta::default();
|
||||||
let insert_a = OperationBuilder::insert("12345").build();
|
let insert_a = Operation::insert("12345");
|
||||||
let retain_a = OperationBuilder::retain(3).build();
|
let retain_a = Operation::retain(3);
|
||||||
delta.add(insert_a.clone());
|
delta.add(insert_a.clone());
|
||||||
delta.add(retain_a.clone());
|
delta.add(retain_a.clone());
|
||||||
let mut iter = DeltaIterator::new(&delta);
|
let mut iter = DeltaIterator::new(&delta);
|
||||||
@ -208,14 +196,11 @@ fn delta_op_seek() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn delta_utf16_code_unit_seek() {
|
fn delta_utf16_code_unit_seek() {
|
||||||
let mut delta = RichTextDelta::default();
|
let mut delta = RichTextDelta::default();
|
||||||
delta.add(OperationBuilder::insert("12345").build());
|
delta.add(Operation::insert("12345"));
|
||||||
|
|
||||||
let mut iter = DeltaIterator::new(&delta);
|
let mut iter = DeltaIterator::new(&delta);
|
||||||
iter.seek::<Utf16CodeUnitMetric>(3);
|
iter.seek::<Utf16CodeUnitMetric>(3);
|
||||||
assert_eq!(
|
assert_eq!(iter.next_op_with_len(2).unwrap(), Operation::insert("45"));
|
||||||
iter.next_op_with_len(2).unwrap(),
|
|
||||||
OperationBuilder::insert("45").build()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -226,91 +211,76 @@ fn delta_utf16_code_unit_seek_with_attributes() {
|
|||||||
.add_attr(RichTextAttribute::Italic(true))
|
.add_attr(RichTextAttribute::Italic(true))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
delta.add(OperationBuilder::insert("1234").attributes(attributes.clone()).build());
|
delta.add(Operation::insert_with_attributes("1234", attributes.clone()));
|
||||||
delta.add(OperationBuilder::insert("\n").build());
|
delta.add(Operation::insert("\n"));
|
||||||
|
|
||||||
let mut iter = DeltaIterator::new(&delta);
|
let mut iter = DeltaIterator::new(&delta);
|
||||||
iter.seek::<Utf16CodeUnitMetric>(0);
|
iter.seek::<Utf16CodeUnitMetric>(0);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
iter.next_op_with_len(4).unwrap(),
|
iter.next_op_with_len(4).unwrap(),
|
||||||
OperationBuilder::insert("1234").attributes(attributes).build(),
|
Operation::insert_with_attributes("1234", attributes),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn delta_next_op_len() {
|
fn delta_next_op_len() {
|
||||||
let mut delta = RichTextDelta::default();
|
let mut delta = RichTextDelta::default();
|
||||||
delta.add(OperationBuilder::insert("12345").build());
|
delta.add(Operation::insert("12345"));
|
||||||
let mut iter = DeltaIterator::new(&delta);
|
let mut iter = DeltaIterator::new(&delta);
|
||||||
assert_eq!(
|
assert_eq!(iter.next_op_with_len(2).unwrap(), Operation::insert("12"));
|
||||||
iter.next_op_with_len(2).unwrap(),
|
assert_eq!(iter.next_op_with_len(2).unwrap(), Operation::insert("34"));
|
||||||
OperationBuilder::insert("12").build()
|
assert_eq!(iter.next_op_with_len(2).unwrap(), Operation::insert("5"));
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
iter.next_op_with_len(2).unwrap(),
|
|
||||||
OperationBuilder::insert("34").build()
|
|
||||||
);
|
|
||||||
assert_eq!(iter.next_op_with_len(2).unwrap(), OperationBuilder::insert("5").build());
|
|
||||||
assert_eq!(iter.next_op_with_len(1), None);
|
assert_eq!(iter.next_op_with_len(1), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn delta_next_op_len_with_chinese() {
|
fn delta_next_op_len_with_chinese() {
|
||||||
let mut delta = RichTextDelta::default();
|
let mut delta = RichTextDelta::default();
|
||||||
delta.add(OperationBuilder::insert("你好").build());
|
delta.add(Operation::insert("你好"));
|
||||||
|
|
||||||
let mut iter = DeltaIterator::new(&delta);
|
let mut iter = DeltaIterator::new(&delta);
|
||||||
assert_eq!(iter.next_op_len().unwrap(), 2);
|
assert_eq!(iter.next_op_len().unwrap(), 2);
|
||||||
assert_eq!(
|
assert_eq!(iter.next_op_with_len(2).unwrap(), Operation::insert("你好"));
|
||||||
iter.next_op_with_len(2).unwrap(),
|
|
||||||
OperationBuilder::insert("你好").build()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn delta_next_op_len_with_english() {
|
fn delta_next_op_len_with_english() {
|
||||||
let mut delta = RichTextDelta::default();
|
let mut delta = RichTextDelta::default();
|
||||||
delta.add(OperationBuilder::insert("ab").build());
|
delta.add(Operation::insert("ab"));
|
||||||
let mut iter = DeltaIterator::new(&delta);
|
let mut iter = DeltaIterator::new(&delta);
|
||||||
assert_eq!(iter.next_op_len().unwrap(), 2);
|
assert_eq!(iter.next_op_len().unwrap(), 2);
|
||||||
assert_eq!(
|
assert_eq!(iter.next_op_with_len(2).unwrap(), Operation::insert("ab"));
|
||||||
iter.next_op_with_len(2).unwrap(),
|
|
||||||
OperationBuilder::insert("ab").build()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn delta_next_op_len_after_seek() {
|
fn delta_next_op_len_after_seek() {
|
||||||
let mut delta = RichTextDelta::default();
|
let mut delta = RichTextDelta::default();
|
||||||
delta.add(OperationBuilder::insert("12345").build());
|
delta.add(Operation::insert("12345"));
|
||||||
let mut iter = DeltaIterator::new(&delta);
|
let mut iter = DeltaIterator::new(&delta);
|
||||||
assert_eq!(iter.next_op_len().unwrap(), 5);
|
assert_eq!(iter.next_op_len().unwrap(), 5);
|
||||||
iter.seek::<Utf16CodeUnitMetric>(3);
|
iter.seek::<Utf16CodeUnitMetric>(3);
|
||||||
assert_eq!(iter.next_op_len().unwrap(), 2);
|
assert_eq!(iter.next_op_len().unwrap(), 2);
|
||||||
assert_eq!(iter.next_op_with_len(1).unwrap(), OperationBuilder::insert("4").build());
|
assert_eq!(iter.next_op_with_len(1).unwrap(), Operation::insert("4"));
|
||||||
assert_eq!(iter.next_op_len().unwrap(), 1);
|
assert_eq!(iter.next_op_len().unwrap(), 1);
|
||||||
assert_eq!(iter.next_op().unwrap(), OperationBuilder::insert("5").build());
|
assert_eq!(iter.next_op().unwrap(), Operation::insert("5"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn delta_next_op_len_none() {
|
fn delta_next_op_len_none() {
|
||||||
let mut delta = RichTextDelta::default();
|
let mut delta = RichTextDelta::default();
|
||||||
delta.add(OperationBuilder::insert("12345").build());
|
delta.add(Operation::insert("12345"));
|
||||||
let mut iter = DeltaIterator::new(&delta);
|
let mut iter = DeltaIterator::new(&delta);
|
||||||
|
|
||||||
assert_eq!(iter.next_op_len().unwrap(), 5);
|
assert_eq!(iter.next_op_len().unwrap(), 5);
|
||||||
assert_eq!(
|
assert_eq!(iter.next_op_with_len(5).unwrap(), Operation::insert("12345"));
|
||||||
iter.next_op_with_len(5).unwrap(),
|
|
||||||
OperationBuilder::insert("12345").build()
|
|
||||||
);
|
|
||||||
assert_eq!(iter.next_op_len(), None);
|
assert_eq!(iter.next_op_len(), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn delta_next_op_with_len_zero() {
|
fn delta_next_op_with_len_zero() {
|
||||||
let mut delta = RichTextDelta::default();
|
let mut delta = RichTextDelta::default();
|
||||||
delta.add(OperationBuilder::insert("12345").build());
|
delta.add(Operation::insert("12345"));
|
||||||
let mut iter = DeltaIterator::new(&delta);
|
let mut iter = DeltaIterator::new(&delta);
|
||||||
assert_eq!(iter.next_op_with_len(0), None,);
|
assert_eq!(iter.next_op_with_len(0), None,);
|
||||||
assert_eq!(iter.next_op_len().unwrap(), 5);
|
assert_eq!(iter.next_op_len().unwrap(), 5);
|
||||||
@ -319,14 +289,14 @@ fn delta_next_op_with_len_zero() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn delta_next_op_with_len_cross_op_return_last() {
|
fn delta_next_op_with_len_cross_op_return_last() {
|
||||||
let mut delta = RichTextDelta::default();
|
let mut delta = RichTextDelta::default();
|
||||||
delta.add(OperationBuilder::insert("12345").build());
|
delta.add(Operation::insert("12345"));
|
||||||
delta.add(OperationBuilder::retain(1).build());
|
delta.add(Operation::retain(1));
|
||||||
delta.add(OperationBuilder::insert("678").build());
|
delta.add(Operation::insert("678"));
|
||||||
|
|
||||||
let mut iter = DeltaIterator::new(&delta);
|
let mut iter = DeltaIterator::new(&delta);
|
||||||
iter.seek::<Utf16CodeUnitMetric>(4);
|
iter.seek::<Utf16CodeUnitMetric>(4);
|
||||||
assert_eq!(iter.next_op_len().unwrap(), 1);
|
assert_eq!(iter.next_op_len().unwrap(), 1);
|
||||||
assert_eq!(iter.next_op_with_len(2).unwrap(), OperationBuilder::retain(1).build());
|
assert_eq!(iter.next_op_with_len(2).unwrap(), Operation::retain(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -363,9 +333,9 @@ fn sequence() {
|
|||||||
fn apply_1000() {
|
fn apply_1000() {
|
||||||
for _ in 0..1 {
|
for _ in 0..1 {
|
||||||
let mut rng = Rng::default();
|
let mut rng = Rng::default();
|
||||||
let s: FlowyStr = rng.gen_string(50).into();
|
let s: OTString = rng.gen_string(50).into();
|
||||||
let delta = rng.gen_delta(&s);
|
let delta = rng.gen_delta(&s);
|
||||||
assert_eq!(s.utf16_size(), delta.utf16_base_len);
|
assert_eq!(s.utf16_len(), delta.utf16_base_len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -453,22 +423,22 @@ fn ops_merging() {
|
|||||||
assert_eq!(delta.ops.len(), 0);
|
assert_eq!(delta.ops.len(), 0);
|
||||||
delta.retain(2, RichTextAttributes::default());
|
delta.retain(2, RichTextAttributes::default());
|
||||||
assert_eq!(delta.ops.len(), 1);
|
assert_eq!(delta.ops.len(), 1);
|
||||||
assert_eq!(delta.ops.last(), Some(&OperationBuilder::retain(2).build()));
|
assert_eq!(delta.ops.last(), Some(&Operation::retain(2)));
|
||||||
delta.retain(3, RichTextAttributes::default());
|
delta.retain(3, RichTextAttributes::default());
|
||||||
assert_eq!(delta.ops.len(), 1);
|
assert_eq!(delta.ops.len(), 1);
|
||||||
assert_eq!(delta.ops.last(), Some(&OperationBuilder::retain(5).build()));
|
assert_eq!(delta.ops.last(), Some(&Operation::retain(5)));
|
||||||
delta.insert("abc", RichTextAttributes::default());
|
delta.insert("abc", RichTextAttributes::default());
|
||||||
assert_eq!(delta.ops.len(), 2);
|
assert_eq!(delta.ops.len(), 2);
|
||||||
assert_eq!(delta.ops.last(), Some(&OperationBuilder::insert("abc").build()));
|
assert_eq!(delta.ops.last(), Some(&Operation::insert("abc")));
|
||||||
delta.insert("xyz", RichTextAttributes::default());
|
delta.insert("xyz", RichTextAttributes::default());
|
||||||
assert_eq!(delta.ops.len(), 2);
|
assert_eq!(delta.ops.len(), 2);
|
||||||
assert_eq!(delta.ops.last(), Some(&OperationBuilder::insert("abcxyz").build()));
|
assert_eq!(delta.ops.last(), Some(&Operation::insert("abcxyz")));
|
||||||
delta.delete(1);
|
delta.delete(1);
|
||||||
assert_eq!(delta.ops.len(), 3);
|
assert_eq!(delta.ops.len(), 3);
|
||||||
assert_eq!(delta.ops.last(), Some(&OperationBuilder::delete(1).build()));
|
assert_eq!(delta.ops.last(), Some(&Operation::delete(1)));
|
||||||
delta.delete(1);
|
delta.delete(1);
|
||||||
assert_eq!(delta.ops.len(), 3);
|
assert_eq!(delta.ops.len(), 3);
|
||||||
assert_eq!(delta.ops.last(), Some(&OperationBuilder::delete(2).build()));
|
assert_eq!(delta.ops.last(), Some(&Operation::delete(2)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -488,16 +458,16 @@ fn compose() {
|
|||||||
let mut rng = Rng::default();
|
let mut rng = Rng::default();
|
||||||
let s = rng.gen_string(20);
|
let s = rng.gen_string(20);
|
||||||
let a = rng.gen_delta(&s);
|
let a = rng.gen_delta(&s);
|
||||||
let after_a: FlowyStr = a.apply(&s).unwrap().into();
|
let after_a: OTString = a.apply(&s).unwrap().into();
|
||||||
assert_eq!(a.utf16_target_len, after_a.utf16_size());
|
assert_eq!(a.utf16_target_len, after_a.utf16_len());
|
||||||
|
|
||||||
let b = rng.gen_delta(&after_a);
|
let b = rng.gen_delta(&after_a);
|
||||||
let after_b: FlowyStr = b.apply(&after_a).unwrap().into();
|
let after_b: OTString = b.apply(&after_a).unwrap().into();
|
||||||
assert_eq!(b.utf16_target_len, after_b.utf16_size());
|
assert_eq!(b.utf16_target_len, after_b.utf16_len());
|
||||||
|
|
||||||
let ab = a.compose(&b).unwrap();
|
let ab = a.compose(&b).unwrap();
|
||||||
assert_eq!(ab.utf16_target_len, b.utf16_target_len);
|
assert_eq!(ab.utf16_target_len, b.utf16_target_len);
|
||||||
let after_ab: FlowyStr = ab.apply(&s).unwrap().into();
|
let after_ab: OTString = ab.apply(&s).unwrap().into();
|
||||||
assert_eq!(after_b, after_ab);
|
assert_eq!(after_b, after_ab);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -621,11 +591,11 @@ fn transform_two_conflict_non_seq_delta() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn delta_invert_no_attribute_delta() {
|
fn delta_invert_no_attribute_delta() {
|
||||||
let mut delta = RichTextDelta::default();
|
let mut delta = RichTextDelta::default();
|
||||||
delta.add(OperationBuilder::insert("123").build());
|
delta.add(Operation::insert("123"));
|
||||||
|
|
||||||
let mut change = RichTextDelta::default();
|
let mut change = RichTextDelta::default();
|
||||||
change.add(OperationBuilder::retain(3).build());
|
change.add(Operation::retain(3));
|
||||||
change.add(OperationBuilder::insert("456").build());
|
change.add(Operation::insert("456"));
|
||||||
let undo = change.invert(&delta);
|
let undo = change.invert(&delta);
|
||||||
|
|
||||||
let new_delta = delta.compose(&change).unwrap();
|
let new_delta = delta.compose(&change).unwrap();
|
||||||
|
@ -11,7 +11,7 @@ fn operation_insert_serialize_test() {
|
|||||||
.add_attr(RichTextAttribute::Bold(true))
|
.add_attr(RichTextAttribute::Bold(true))
|
||||||
.add_attr(RichTextAttribute::Italic(true))
|
.add_attr(RichTextAttribute::Italic(true))
|
||||||
.build();
|
.build();
|
||||||
let operation = OperationBuilder::insert("123").attributes(attributes).build();
|
let operation = Operation::insert_with_attributes("123", attributes);
|
||||||
let json = serde_json::to_string(&operation).unwrap();
|
let json = serde_json::to_string(&operation).unwrap();
|
||||||
eprintln!("{}", json);
|
eprintln!("{}", json);
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ fn attributes_serialize_test() {
|
|||||||
.add_attr(RichTextAttribute::Bold(true))
|
.add_attr(RichTextAttribute::Bold(true))
|
||||||
.add_attr(RichTextAttribute::Italic(true))
|
.add_attr(RichTextAttribute::Italic(true))
|
||||||
.build();
|
.build();
|
||||||
let retain = OperationBuilder::insert("123").attributes(attributes).build();
|
let retain = Operation::insert_with_attributes("123", attributes);
|
||||||
|
|
||||||
let json = serde_json::to_string(&retain).unwrap();
|
let json = serde_json::to_string(&retain).unwrap();
|
||||||
eprintln!("{}", json);
|
eprintln!("{}", json);
|
||||||
@ -56,7 +56,7 @@ fn delta_serialize_multi_attribute_test() {
|
|||||||
.add_attr(RichTextAttribute::Bold(true))
|
.add_attr(RichTextAttribute::Bold(true))
|
||||||
.add_attr(RichTextAttribute::Italic(true))
|
.add_attr(RichTextAttribute::Italic(true))
|
||||||
.build();
|
.build();
|
||||||
let retain = OperationBuilder::insert("123").attributes(attributes).build();
|
let retain = Operation::insert_with_attributes("123", attributes);
|
||||||
|
|
||||||
delta.add(retain);
|
delta.add(retain);
|
||||||
delta.add(Operation::Retain(5.into()));
|
delta.add(Operation::Retain(5.into()));
|
||||||
|
@ -434,7 +434,7 @@ mod tests {
|
|||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
|
|
||||||
use flowy_folder_data_model::revision::{AppRevision, TrashRevision, ViewRevision, WorkspaceRevision};
|
use flowy_folder_data_model::revision::{AppRevision, TrashRevision, ViewRevision, WorkspaceRevision};
|
||||||
use lib_ot::core::{OperationTransformable, PlainTextDelta, PlainTextDeltaBuilder};
|
use lib_ot::core::{OperationTransform, PlainTextDelta, PlainTextDeltaBuilder};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn folder_add_workspace() {
|
fn folder_add_workspace() {
|
||||||
|
@ -4,7 +4,7 @@ use crate::util::{cal_diff, make_delta_from_revisions};
|
|||||||
use flowy_grid_data_model::revision::{
|
use flowy_grid_data_model::revision::{
|
||||||
gen_block_id, gen_row_id, CellRevision, GridBlockRevision, RowMetaChangeset, RowRevision,
|
gen_block_id, gen_row_id, CellRevision, GridBlockRevision, RowMetaChangeset, RowRevision,
|
||||||
};
|
};
|
||||||
use lib_ot::core::{OperationTransformable, PhantomAttributes, PlainTextDelta, PlainTextDeltaBuilder};
|
use lib_ot::core::{OperationTransform, PhantomAttributes, PlainTextDelta, PlainTextDeltaBuilder};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -9,7 +9,7 @@ use flowy_grid_data_model::revision::{
|
|||||||
GridLayoutRevision, GridRevision, GridSettingRevision, GridSortRevision,
|
GridLayoutRevision, GridRevision, GridSettingRevision, GridSortRevision,
|
||||||
};
|
};
|
||||||
use lib_infra::util::move_vec_element;
|
use lib_infra::util::move_vec_element;
|
||||||
use lib_ot::core::{OperationTransformable, PhantomAttributes, PlainTextDelta, PlainTextDeltaBuilder};
|
use lib_ot::core::{OperationTransform, PhantomAttributes, PlainTextDelta, PlainTextDeltaBuilder};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::{entities::folder::FolderDelta, errors::CollaborateError, synchronizer::RevisionSyncObject};
|
use crate::{entities::folder::FolderDelta, errors::CollaborateError, synchronizer::RevisionSyncObject};
|
||||||
use lib_ot::core::{OperationTransformable, PhantomAttributes, PlainTextDelta};
|
use lib_ot::core::{OperationTransform, PhantomAttributes, PlainTextDelta};
|
||||||
|
|
||||||
pub struct ServerFolder {
|
pub struct ServerFolder {
|
||||||
folder_id: String,
|
folder_id: String,
|
||||||
|
@ -7,9 +7,9 @@ use crate::{
|
|||||||
errors::{CollaborateError, CollaborateResult},
|
errors::{CollaborateError, CollaborateResult},
|
||||||
};
|
};
|
||||||
use dissimilar::Chunk;
|
use dissimilar::Chunk;
|
||||||
use lib_ot::core::{DeltaBuilder, FlowyStr};
|
use lib_ot::core::{DeltaBuilder, OTString};
|
||||||
use lib_ot::{
|
use lib_ot::{
|
||||||
core::{Attributes, Delta, OperationTransformable, NEW_LINE, WHITESPACE},
|
core::{Attributes, Delta, OperationTransform, NEW_LINE, WHITESPACE},
|
||||||
rich_text::RichTextDelta,
|
rich_text::RichTextDelta,
|
||||||
};
|
};
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
@ -208,10 +208,10 @@ pub fn cal_diff<T: Attributes>(old: String, new: String) -> Option<Delta<T>> {
|
|||||||
for chunk in &chunks {
|
for chunk in &chunks {
|
||||||
match chunk {
|
match chunk {
|
||||||
Chunk::Equal(s) => {
|
Chunk::Equal(s) => {
|
||||||
delta_builder = delta_builder.retain(FlowyStr::from(*s).utf16_size());
|
delta_builder = delta_builder.retain(OTString::from(*s).utf16_len());
|
||||||
}
|
}
|
||||||
Chunk::Delete(s) => {
|
Chunk::Delete(s) => {
|
||||||
delta_builder = delta_builder.delete(FlowyStr::from(*s).utf16_size());
|
delta_builder = delta_builder.delete(OTString::from(*s).utf16_len());
|
||||||
}
|
}
|
||||||
Chunk::Insert(s) => {
|
Chunk::Insert(s) => {
|
||||||
delta_builder = delta_builder.insert(*s);
|
delta_builder = delta_builder.insert(*s);
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use crate::core::delta::{trim, Delta};
|
use crate::core::delta::{trim, Delta};
|
||||||
use crate::core::operation::{Attributes, PhantomAttributes};
|
use crate::core::operation::{Attributes, PhantomAttributes};
|
||||||
|
use crate::core::Operation;
|
||||||
|
|
||||||
pub type PlainTextDeltaBuilder = DeltaBuilder<PhantomAttributes>;
|
pub type PlainTextDeltaBuilder = DeltaBuilder<PhantomAttributes>;
|
||||||
|
|
||||||
@ -7,6 +8,16 @@ pub type PlainTextDeltaBuilder = DeltaBuilder<PhantomAttributes>;
|
|||||||
///
|
///
|
||||||
/// Note that all edit operations must be sorted; the start point of each
|
/// Note that all edit operations must be sorted; the start point of each
|
||||||
/// interval must be no less than the end point of the previous one.
|
/// interval must be no less than the end point of the previous one.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use lib_ot::core::PlainTextDeltaBuilder;
|
||||||
|
/// let delta = PlainTextDeltaBuilder::new()
|
||||||
|
/// .insert("AppFlowy")
|
||||||
|
/// .build();
|
||||||
|
/// assert_eq!(delta.content_str().unwrap(), "AppFlowy");
|
||||||
|
/// ```
|
||||||
pub struct DeltaBuilder<T: Attributes> {
|
pub struct DeltaBuilder<T: Attributes> {
|
||||||
delta: Delta<T>,
|
delta: Delta<T>,
|
||||||
}
|
}
|
||||||
@ -28,8 +39,26 @@ where
|
|||||||
DeltaBuilder::default()
|
DeltaBuilder::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_operations(operations: Vec<Operation<T>>) -> Delta<T> {
|
||||||
|
let mut delta = DeltaBuilder::default().build();
|
||||||
|
operations.into_iter().for_each(|operation| {
|
||||||
|
delta.add(operation);
|
||||||
|
});
|
||||||
|
delta
|
||||||
|
}
|
||||||
|
|
||||||
/// Retain the 'n' characters with the attributes. Use 'retain' instead if you don't
|
/// Retain the 'n' characters with the attributes. Use 'retain' instead if you don't
|
||||||
/// need any attributes.
|
/// need any attributes.
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use lib_ot::rich_text::{RichTextAttribute, RichTextDelta, RichTextDeltaBuilder};
|
||||||
|
///
|
||||||
|
/// let mut attribute = RichTextAttribute::Bold(true);
|
||||||
|
/// let delta = RichTextDeltaBuilder::new().retain_with_attributes(7, attribute.into()).build();
|
||||||
|
///
|
||||||
|
/// assert_eq!(delta.to_json_str(), r#"[{"retain":7,"attributes":{"bold":true}}]"#);
|
||||||
|
/// ```
|
||||||
pub fn retain_with_attributes(mut self, n: usize, attrs: T) -> Self {
|
pub fn retain_with_attributes(mut self, n: usize, attrs: T) -> Self {
|
||||||
self.delta.retain(n, attrs);
|
self.delta.retain(n, attrs);
|
||||||
self
|
self
|
||||||
@ -41,6 +70,24 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Deletes the given interval. Panics if interval is not properly sorted.
|
/// Deletes the given interval. Panics if interval is not properly sorted.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use lib_ot::core::{OperationTransform, PlainTextDeltaBuilder};
|
||||||
|
///
|
||||||
|
/// let delta = PlainTextDeltaBuilder::new()
|
||||||
|
/// .insert("AppFlowy...")
|
||||||
|
/// .build();
|
||||||
|
///
|
||||||
|
/// let changeset = PlainTextDeltaBuilder::new()
|
||||||
|
/// .retain(8)
|
||||||
|
/// .delete(3)
|
||||||
|
/// .build();
|
||||||
|
///
|
||||||
|
/// let new_delta = delta.compose(&changeset).unwrap();
|
||||||
|
/// assert_eq!(new_delta.content_str().unwrap(), "AppFlowy");
|
||||||
|
/// ```
|
||||||
pub fn delete(mut self, n: usize) -> Self {
|
pub fn delete(mut self, n: usize) -> Self {
|
||||||
self.delta.delete(n);
|
self.delta.delete(n);
|
||||||
self
|
self
|
||||||
@ -58,6 +105,25 @@ where
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Removes trailing retain operation with empty attributes
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use lib_ot::core::{OperationTransform, PlainTextDeltaBuilder};
|
||||||
|
/// use lib_ot::rich_text::{RichTextAttribute, RichTextDeltaBuilder};
|
||||||
|
/// let delta = PlainTextDeltaBuilder::new()
|
||||||
|
/// .retain(3)
|
||||||
|
/// .trim()
|
||||||
|
/// .build();
|
||||||
|
/// assert_eq!(delta.ops.len(), 0);
|
||||||
|
///
|
||||||
|
/// let delta = RichTextDeltaBuilder::new()
|
||||||
|
/// .retain_with_attributes(3, RichTextAttribute::Bold(true).into())
|
||||||
|
/// .trim()
|
||||||
|
/// .build();
|
||||||
|
/// assert_eq!(delta.ops.len(), 1);
|
||||||
|
/// ```
|
||||||
pub fn trim(mut self) -> Self {
|
pub fn trim(mut self) -> Self {
|
||||||
trim(&mut self.delta);
|
trim(&mut self.delta);
|
||||||
self
|
self
|
||||||
|
@ -29,11 +29,11 @@ where
|
|||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use lib_ot::core::{DeltaIterator, Interval, OperationBuilder};
|
/// use lib_ot::core::{DeltaIterator, Interval, Operation};
|
||||||
/// use lib_ot::rich_text::RichTextDelta;
|
/// use lib_ot::rich_text::RichTextDelta;
|
||||||
/// let mut delta = RichTextDelta::default();
|
/// let mut delta = RichTextDelta::default();
|
||||||
/// let op_1 = OperationBuilder::insert("123").build();
|
/// let op_1 = Operation::insert("123");
|
||||||
/// let op_2 = OperationBuilder::insert("4").build();
|
/// let op_2 = Operation::insert("4");
|
||||||
/// delta.add(op_1.clone());
|
/// delta.add(op_1.clone());
|
||||||
/// delta.add(op_2.clone());
|
/// delta.add(op_2.clone());
|
||||||
/// assert_eq!(DeltaIterator::from_interval(&delta, Interval::new(0, 3)).ops(), vec![op_1.clone()]);
|
/// assert_eq!(DeltaIterator::from_interval(&delta, Interval::new(0, 3)).ops(), vec![op_1.clone()]);
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
use crate::errors::{ErrorBuilder, OTError, OTErrorCode};
|
use crate::errors::{ErrorBuilder, OTError, OTErrorCode};
|
||||||
|
|
||||||
use crate::core::delta::{DeltaIterator, MAX_IV_LEN};
|
use crate::core::delta::{DeltaIterator, MAX_IV_LEN};
|
||||||
use crate::core::flowy_str::FlowyStr;
|
use crate::core::flowy_str::OTString;
|
||||||
use crate::core::interval::Interval;
|
use crate::core::interval::Interval;
|
||||||
use crate::core::operation::{Attributes, Operation, OperationBuilder, OperationTransformable, PhantomAttributes};
|
use crate::core::operation::{Attributes, Operation, OperationTransform, PhantomAttributes};
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
use std::{
|
use std::{
|
||||||
@ -112,18 +112,18 @@ where
|
|||||||
if let Some(Operation::Delete(n_last)) = self.ops.last_mut() {
|
if let Some(Operation::Delete(n_last)) = self.ops.last_mut() {
|
||||||
*n_last += n;
|
*n_last += n;
|
||||||
} else {
|
} else {
|
||||||
self.ops.push(OperationBuilder::delete(n).build());
|
self.ops.push(Operation::delete(n));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creating a [Insert] operation with string, [s].
|
/// Creating a [Insert] operation with string, [s].
|
||||||
pub fn insert(&mut self, s: &str, attributes: T) {
|
pub fn insert(&mut self, s: &str, attributes: T) {
|
||||||
let s: FlowyStr = s.into();
|
let s: OTString = s.into();
|
||||||
if s.is_empty() {
|
if s.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.utf16_target_len += s.utf16_size();
|
self.utf16_target_len += s.utf16_len();
|
||||||
let new_last = match self.ops.as_mut_slice() {
|
let new_last = match self.ops.as_mut_slice() {
|
||||||
[.., Operation::<T>::Insert(insert)] => {
|
[.., Operation::<T>::Insert(insert)] => {
|
||||||
//
|
//
|
||||||
@ -135,10 +135,10 @@ where
|
|||||||
}
|
}
|
||||||
[.., op_last @ Operation::<T>::Delete(_)] => {
|
[.., op_last @ Operation::<T>::Delete(_)] => {
|
||||||
let new_last = op_last.clone();
|
let new_last = op_last.clone();
|
||||||
*op_last = OperationBuilder::<T>::insert(&s).attributes(attributes).build();
|
*op_last = Operation::<T>::insert_with_attributes(&s, attributes);
|
||||||
Some(new_last)
|
Some(new_last)
|
||||||
}
|
}
|
||||||
_ => Some(OperationBuilder::<T>::insert(&s).attributes(attributes).build()),
|
_ => Some(Operation::<T>::insert_with_attributes(&s, attributes)),
|
||||||
};
|
};
|
||||||
|
|
||||||
match new_last {
|
match new_last {
|
||||||
@ -160,8 +160,7 @@ where
|
|||||||
self.ops.push(new_op);
|
self.ops.push(new_op);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.ops
|
self.ops.push(Operation::<T>::retain_with_attributes(n, attributes));
|
||||||
.push(OperationBuilder::<T>::retain(n).attributes(attributes).build());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,18 +189,18 @@ where
|
|||||||
/// assert_eq!("hello, AppFlowy", &after_b);
|
/// assert_eq!("hello, AppFlowy", &after_b);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn apply(&self, applied_str: &str) -> Result<String, OTError> {
|
pub fn apply(&self, applied_str: &str) -> Result<String, OTError> {
|
||||||
let applied_str: FlowyStr = applied_str.into();
|
let applied_str: OTString = applied_str.into();
|
||||||
if applied_str.utf16_size() != self.utf16_base_len {
|
if applied_str.utf16_len() != self.utf16_base_len {
|
||||||
return Err(ErrorBuilder::new(OTErrorCode::IncompatibleLength)
|
return Err(ErrorBuilder::new(OTErrorCode::IncompatibleLength)
|
||||||
.msg(format!(
|
.msg(format!(
|
||||||
"Expected: {}, but received: {}",
|
"Expected: {}, but received: {}",
|
||||||
self.utf16_base_len,
|
self.utf16_base_len,
|
||||||
applied_str.utf16_size()
|
applied_str.utf16_len()
|
||||||
))
|
))
|
||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
let mut new_s = String::new();
|
let mut new_s = String::new();
|
||||||
let code_point_iter = &mut applied_str.utf16_code_unit_iter();
|
let code_point_iter = &mut applied_str.utf16_iter();
|
||||||
for op in &self.ops {
|
for op in &self.ops {
|
||||||
match &op {
|
match &op {
|
||||||
Operation::Retain(retain) => {
|
Operation::Retain(retain) => {
|
||||||
@ -247,8 +246,8 @@ where
|
|||||||
///
|
///
|
||||||
pub fn invert_str(&self, inverted_s: &str) -> Self {
|
pub fn invert_str(&self, inverted_s: &str) -> Self {
|
||||||
let mut inverted = Delta::default();
|
let mut inverted = Delta::default();
|
||||||
let inverted_s: FlowyStr = inverted_s.into();
|
let inverted_s: OTString = inverted_s.into();
|
||||||
let code_point_iter = &mut inverted_s.utf16_code_unit_iter();
|
let code_point_iter = &mut inverted_s.utf16_iter();
|
||||||
|
|
||||||
for op in &self.ops {
|
for op in &self.ops {
|
||||||
match &op {
|
match &op {
|
||||||
@ -289,7 +288,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> OperationTransformable for Delta<T>
|
impl<T> OperationTransform for Delta<T>
|
||||||
where
|
where
|
||||||
T: Attributes,
|
T: Attributes,
|
||||||
{
|
{
|
||||||
@ -319,10 +318,10 @@ where
|
|||||||
|
|
||||||
let op = iter
|
let op = iter
|
||||||
.next_op_with_len(length)
|
.next_op_with_len(length)
|
||||||
.unwrap_or_else(|| OperationBuilder::retain(length).build());
|
.unwrap_or_else(|| Operation::retain(length));
|
||||||
let other_op = other_iter
|
let other_op = other_iter
|
||||||
.next_op_with_len(length)
|
.next_op_with_len(length)
|
||||||
.unwrap_or_else(|| OperationBuilder::retain(length).build());
|
.unwrap_or_else(|| Operation::retain(length));
|
||||||
|
|
||||||
// debug_assert_eq!(op.len(), other_op.len(), "Composing delta failed,");
|
// debug_assert_eq!(op.len(), other_op.len(), "Composing delta failed,");
|
||||||
|
|
||||||
@ -330,16 +329,12 @@ where
|
|||||||
(Operation::Retain(retain), Operation::Retain(other_retain)) => {
|
(Operation::Retain(retain), Operation::Retain(other_retain)) => {
|
||||||
let composed_attrs = retain.attributes.compose(&other_retain.attributes)?;
|
let composed_attrs = retain.attributes.compose(&other_retain.attributes)?;
|
||||||
|
|
||||||
new_delta.add(OperationBuilder::retain(retain.n).attributes(composed_attrs).build())
|
new_delta.add(Operation::retain_with_attributes(retain.n, composed_attrs))
|
||||||
}
|
}
|
||||||
(Operation::Insert(insert), Operation::Retain(other_retain)) => {
|
(Operation::Insert(insert), Operation::Retain(other_retain)) => {
|
||||||
let mut composed_attrs = insert.attributes.compose(&other_retain.attributes)?;
|
let mut composed_attrs = insert.attributes.compose(&other_retain.attributes)?;
|
||||||
composed_attrs.remove_empty();
|
composed_attrs.remove_empty();
|
||||||
new_delta.add(
|
new_delta.add(Operation::insert_with_attributes(op.get_data(), composed_attrs))
|
||||||
OperationBuilder::insert(op.get_data())
|
|
||||||
.attributes(composed_attrs)
|
|
||||||
.build(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
(Operation::Retain(_), Operation::Delete(_)) => {
|
(Operation::Retain(_), Operation::Delete(_)) => {
|
||||||
new_delta.add(other_op);
|
new_delta.add(other_op);
|
||||||
@ -402,7 +397,7 @@ where
|
|||||||
Ordering::Less => {
|
Ordering::Less => {
|
||||||
a_prime.retain(retain.n, composed_attrs.clone());
|
a_prime.retain(retain.n, composed_attrs.clone());
|
||||||
b_prime.retain(retain.n, composed_attrs.clone());
|
b_prime.retain(retain.n, composed_attrs.clone());
|
||||||
next_op2 = Some(OperationBuilder::retain(o_retain.n - retain.n).build());
|
next_op2 = Some(Operation::retain(o_retain.n - retain.n));
|
||||||
next_op1 = ops1.next();
|
next_op1 = ops1.next();
|
||||||
}
|
}
|
||||||
Ordering::Equal => {
|
Ordering::Equal => {
|
||||||
@ -414,14 +409,14 @@ where
|
|||||||
Ordering::Greater => {
|
Ordering::Greater => {
|
||||||
a_prime.retain(o_retain.n, composed_attrs.clone());
|
a_prime.retain(o_retain.n, composed_attrs.clone());
|
||||||
b_prime.retain(o_retain.n, composed_attrs.clone());
|
b_prime.retain(o_retain.n, composed_attrs.clone());
|
||||||
next_op1 = Some(OperationBuilder::retain(retain.n - o_retain.n).build());
|
next_op1 = Some(Operation::retain(retain.n - o_retain.n));
|
||||||
next_op2 = ops2.next();
|
next_op2 = ops2.next();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
(Some(Operation::Delete(i)), Some(Operation::Delete(j))) => match i.cmp(j) {
|
(Some(Operation::Delete(i)), Some(Operation::Delete(j))) => match i.cmp(j) {
|
||||||
Ordering::Less => {
|
Ordering::Less => {
|
||||||
next_op2 = Some(OperationBuilder::delete(*j - *i).build());
|
next_op2 = Some(Operation::delete(*j - *i));
|
||||||
next_op1 = ops1.next();
|
next_op1 = ops1.next();
|
||||||
}
|
}
|
||||||
Ordering::Equal => {
|
Ordering::Equal => {
|
||||||
@ -429,7 +424,7 @@ where
|
|||||||
next_op2 = ops2.next();
|
next_op2 = ops2.next();
|
||||||
}
|
}
|
||||||
Ordering::Greater => {
|
Ordering::Greater => {
|
||||||
next_op1 = Some(OperationBuilder::delete(*i - *j).build());
|
next_op1 = Some(Operation::delete(*i - *j));
|
||||||
next_op2 = ops2.next();
|
next_op2 = ops2.next();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -437,7 +432,7 @@ where
|
|||||||
match i.cmp(o_retain) {
|
match i.cmp(o_retain) {
|
||||||
Ordering::Less => {
|
Ordering::Less => {
|
||||||
a_prime.delete(*i);
|
a_prime.delete(*i);
|
||||||
next_op2 = Some(OperationBuilder::retain(o_retain.n - *i).build());
|
next_op2 = Some(Operation::retain(o_retain.n - *i));
|
||||||
next_op1 = ops1.next();
|
next_op1 = ops1.next();
|
||||||
}
|
}
|
||||||
Ordering::Equal => {
|
Ordering::Equal => {
|
||||||
@ -447,7 +442,7 @@ where
|
|||||||
}
|
}
|
||||||
Ordering::Greater => {
|
Ordering::Greater => {
|
||||||
a_prime.delete(o_retain.n);
|
a_prime.delete(o_retain.n);
|
||||||
next_op1 = Some(OperationBuilder::delete(*i - o_retain.n).build());
|
next_op1 = Some(Operation::delete(*i - o_retain.n));
|
||||||
next_op2 = ops2.next();
|
next_op2 = ops2.next();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -456,7 +451,7 @@ where
|
|||||||
match retain.cmp(j) {
|
match retain.cmp(j) {
|
||||||
Ordering::Less => {
|
Ordering::Less => {
|
||||||
b_prime.delete(retain.n);
|
b_prime.delete(retain.n);
|
||||||
next_op2 = Some(OperationBuilder::delete(*j - retain.n).build());
|
next_op2 = Some(Operation::delete(*j - retain.n));
|
||||||
next_op1 = ops1.next();
|
next_op1 = ops1.next();
|
||||||
}
|
}
|
||||||
Ordering::Equal => {
|
Ordering::Equal => {
|
||||||
@ -466,7 +461,7 @@ where
|
|||||||
}
|
}
|
||||||
Ordering::Greater => {
|
Ordering::Greater => {
|
||||||
b_prime.delete(*j);
|
b_prime.delete(*j);
|
||||||
next_op1 = Some(OperationBuilder::retain(retain.n - *j).build());
|
next_op1 = Some(Operation::retain(retain.n - *j));
|
||||||
next_op2 = ops2.next();
|
next_op2 = ops2.next();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -568,6 +563,17 @@ impl<T> Delta<T>
|
|||||||
where
|
where
|
||||||
T: Attributes + DeserializeOwned,
|
T: Attributes + DeserializeOwned,
|
||||||
{
|
{
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use lib_ot::core::DeltaBuilder;
|
||||||
|
/// use lib_ot::rich_text::{RichTextDelta};
|
||||||
|
/// let json = r#"[
|
||||||
|
/// {"retain":7,"attributes":{"bold":null}}
|
||||||
|
/// ]"#;
|
||||||
|
/// let delta = RichTextDelta::from_json_str(json).unwrap();
|
||||||
|
/// assert_eq!(delta.to_json_str(), r#"[{"retain":7,"attributes":{"bold":""}}]"#);
|
||||||
|
/// ```
|
||||||
pub fn from_json_str(json: &str) -> Result<Self, OTError> {
|
pub fn from_json_str(json: &str) -> Result<Self, OTError> {
|
||||||
let delta = serde_json::from_str(json).map_err(|e| {
|
let delta = serde_json::from_str(json).map_err(|e| {
|
||||||
tracing::trace!("Deserialize failed: {:?}", e);
|
tracing::trace!("Deserialize failed: {:?}", e);
|
||||||
|
@ -7,6 +7,18 @@ use std::ops::{Deref, DerefMut};
|
|||||||
|
|
||||||
pub(crate) const MAX_IV_LEN: usize = i32::MAX as usize;
|
pub(crate) const MAX_IV_LEN: usize = i32::MAX as usize;
|
||||||
|
|
||||||
|
/// Retain the 'n' characters with the attributes. Use 'retain' instead if you don't
|
||||||
|
/// need any attributes.
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use lib_ot::rich_text::{RichTextAttribute, RichTextDelta, RichTextDeltaBuilder};
|
||||||
|
///
|
||||||
|
/// let mut attribute = RichTextAttribute::Bold(true);
|
||||||
|
/// let delta = RichTextDeltaBuilder::new().retain_with_attributes(7, attribute.into()).build();
|
||||||
|
///
|
||||||
|
/// assert_eq!(delta.to_json_str(), r#"[{"retain":7,"attributes":{"bold":true}}]"#);
|
||||||
|
/// ```
|
||||||
pub struct DeltaIterator<'a, T: Attributes> {
|
pub struct DeltaIterator<'a, T: Attributes> {
|
||||||
cursor: DeltaCursor<'a, T>,
|
cursor: DeltaCursor<'a, T>,
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,51 @@
|
|||||||
use serde::{de, de::Visitor, Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{de, de::Visitor, Deserialize, Deserializer, Serialize, Serializer};
|
||||||
use std::{fmt, fmt::Formatter};
|
use std::{fmt, fmt::Formatter};
|
||||||
|
|
||||||
|
/// [OTString] uses [String] as its inner container.
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct FlowyStr(pub String);
|
pub struct OTString(pub String);
|
||||||
|
|
||||||
impl FlowyStr {
|
impl OTString {
|
||||||
// https://stackoverflow.com/questions/2241348/what-is-unicode-utf-8-utf-16
|
/// Returns the number of UTF-16 code units in this string.
|
||||||
pub fn utf16_size(&self) -> usize {
|
///
|
||||||
|
/// The length of strings behaves differently in different languages. For example: [Dart] string's
|
||||||
|
/// length is calculated with UTF-16 code units. The method [utf16_len] returns the length of a
|
||||||
|
/// String in UTF-16 code units.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use lib_ot::core::OTString;
|
||||||
|
/// let utf16_len = OTString::from("👋").utf16_len();
|
||||||
|
/// assert_eq!(utf16_len, 2);
|
||||||
|
/// let bytes_len = String::from("👋").len();
|
||||||
|
/// assert_eq!(bytes_len, 4);
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
pub fn utf16_len(&self) -> usize {
|
||||||
count_utf16_code_units(&self.0)
|
count_utf16_code_units(&self.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn utf16_code_unit_iter(&self) -> Utf16CodeUnitIterator {
|
pub fn utf16_iter(&self) -> Utf16CodeUnitIterator {
|
||||||
Utf16CodeUnitIterator::new(self)
|
Utf16CodeUnitIterator::new(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a new string with the given [Interval]
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use lib_ot::core::{OTString, Interval};
|
||||||
|
/// let s: OTString = "你好\n😁".into();
|
||||||
|
/// assert_eq!(s.utf16_len(), 5);
|
||||||
|
/// let output1 = s.sub_str(Interval::new(0, 2)).unwrap();
|
||||||
|
/// assert_eq!(output1, "你好");
|
||||||
|
///
|
||||||
|
/// let output2 = s.sub_str(Interval::new(2, 3)).unwrap();
|
||||||
|
/// assert_eq!(output2, "\n");
|
||||||
|
///
|
||||||
|
/// let output3 = s.sub_str(Interval::new(3, 5)).unwrap();
|
||||||
|
/// assert_eq!(output3, "😁");
|
||||||
|
/// ```
|
||||||
pub fn sub_str(&self, interval: Interval) -> Option<String> {
|
pub fn sub_str(&self, interval: Interval) -> Option<String> {
|
||||||
let mut iter = Utf16CodeUnitIterator::new(self);
|
let mut iter = Utf16CodeUnitIterator::new(self);
|
||||||
let mut buf = vec![];
|
let mut buf = vec![];
|
||||||
@ -33,13 +65,33 @@ impl FlowyStr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return a new string with the given [Interval]
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use lib_ot::core::OTString;
|
||||||
|
/// let s: OTString = "👋😁👋".into(); ///
|
||||||
|
/// let mut iter = s.utf16_code_point_iter();
|
||||||
|
/// assert_eq!(iter.next().unwrap(), "👋".to_string());
|
||||||
|
/// assert_eq!(iter.next().unwrap(), "😁".to_string());
|
||||||
|
/// assert_eq!(iter.next().unwrap(), "👋".to_string());
|
||||||
|
/// assert_eq!(iter.next(), None);
|
||||||
|
///
|
||||||
|
/// let s: OTString = "👋12ab一二👋".into(); ///
|
||||||
|
/// let mut iter = s.utf16_code_point_iter();
|
||||||
|
/// assert_eq!(iter.next().unwrap(), "👋".to_string());
|
||||||
|
/// assert_eq!(iter.next().unwrap(), "1".to_string());
|
||||||
|
/// assert_eq!(iter.next().unwrap(), "2".to_string());
|
||||||
|
///
|
||||||
|
/// assert_eq!(iter.skip(OTString::from("ab一二").utf16_len()).next().unwrap(), "👋".to_string());
|
||||||
|
/// ```
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn utf16_code_point_iter(&self) -> FlowyUtf16CodePointIterator {
|
pub fn utf16_code_point_iter(&self) -> FlowyUtf16CodePointIterator {
|
||||||
FlowyUtf16CodePointIterator::new(self, 0)
|
FlowyUtf16CodePointIterator::new(self, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::ops::Deref for FlowyStr {
|
impl std::ops::Deref for OTString {
|
||||||
type Target = String;
|
type Target = String;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
@ -47,46 +99,46 @@ impl std::ops::Deref for FlowyStr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::ops::DerefMut for FlowyStr {
|
impl std::ops::DerefMut for OTString {
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
&mut self.0
|
&mut self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::From<String> for FlowyStr {
|
impl std::convert::From<String> for OTString {
|
||||||
fn from(s: String) -> Self {
|
fn from(s: String) -> Self {
|
||||||
FlowyStr(s)
|
OTString(s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::From<&str> for FlowyStr {
|
impl std::convert::From<&str> for OTString {
|
||||||
fn from(s: &str) -> Self {
|
fn from(s: &str) -> Self {
|
||||||
s.to_owned().into()
|
s.to_owned().into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for FlowyStr {
|
impl std::fmt::Display for OTString {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
f.write_str(&self.0)
|
f.write_str(&self.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::ops::Add<&str> for FlowyStr {
|
impl std::ops::Add<&str> for OTString {
|
||||||
type Output = FlowyStr;
|
type Output = OTString;
|
||||||
|
|
||||||
fn add(self, rhs: &str) -> FlowyStr {
|
fn add(self, rhs: &str) -> OTString {
|
||||||
let new_value = self.0 + rhs;
|
let new_value = self.0 + rhs;
|
||||||
new_value.into()
|
new_value.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::ops::AddAssign<&str> for FlowyStr {
|
impl std::ops::AddAssign<&str> for OTString {
|
||||||
fn add_assign(&mut self, rhs: &str) {
|
fn add_assign(&mut self, rhs: &str) {
|
||||||
self.0 += rhs;
|
self.0 += rhs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for FlowyStr {
|
impl Serialize for OTString {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
S: Serializer,
|
S: Serializer,
|
||||||
@ -95,15 +147,15 @@ impl Serialize for FlowyStr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for FlowyStr {
|
impl<'de> Deserialize<'de> for OTString {
|
||||||
fn deserialize<D>(deserializer: D) -> Result<FlowyStr, D::Error>
|
fn deserialize<D>(deserializer: D) -> Result<OTString, D::Error>
|
||||||
where
|
where
|
||||||
D: Deserializer<'de>,
|
D: Deserializer<'de>,
|
||||||
{
|
{
|
||||||
struct FlowyStrVisitor;
|
struct OTStringVisitor;
|
||||||
|
|
||||||
impl<'de> Visitor<'de> for FlowyStrVisitor {
|
impl<'de> Visitor<'de> for OTStringVisitor {
|
||||||
type Value = FlowyStr;
|
type Value = OTString;
|
||||||
|
|
||||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
formatter.write_str("a str")
|
formatter.write_str("a str")
|
||||||
@ -116,19 +168,19 @@ impl<'de> Deserialize<'de> for FlowyStr {
|
|||||||
Ok(s.into())
|
Ok(s.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
deserializer.deserialize_str(FlowyStrVisitor)
|
deserializer.deserialize_str(OTStringVisitor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Utf16CodeUnitIterator<'a> {
|
pub struct Utf16CodeUnitIterator<'a> {
|
||||||
s: &'a FlowyStr,
|
s: &'a OTString,
|
||||||
byte_offset: usize,
|
byte_offset: usize,
|
||||||
utf16_offset: usize,
|
utf16_offset: usize,
|
||||||
utf16_count: usize,
|
utf16_count: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Utf16CodeUnitIterator<'a> {
|
impl<'a> Utf16CodeUnitIterator<'a> {
|
||||||
pub fn new(s: &'a FlowyStr) -> Self {
|
pub fn new(s: &'a OTString) -> Self {
|
||||||
Utf16CodeUnitIterator {
|
Utf16CodeUnitIterator {
|
||||||
s,
|
s,
|
||||||
byte_offset: 0,
|
byte_offset: 0,
|
||||||
@ -167,12 +219,12 @@ impl<'a> Iterator for Utf16CodeUnitIterator<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct FlowyUtf16CodePointIterator<'a> {
|
pub struct FlowyUtf16CodePointIterator<'a> {
|
||||||
s: &'a FlowyStr,
|
s: &'a OTString,
|
||||||
offset: usize,
|
offset: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> FlowyUtf16CodePointIterator<'a> {
|
impl<'a> FlowyUtf16CodePointIterator<'a> {
|
||||||
pub fn new(s: &'a FlowyStr, offset: usize) -> Self {
|
pub fn new(s: &'a OTString, offset: usize) -> Self {
|
||||||
FlowyUtf16CodePointIterator { s, offset }
|
FlowyUtf16CodePointIterator { s, offset }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -226,15 +278,15 @@ pub fn len_utf8_from_first_byte(b: u8) -> usize {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::core::flowy_str::FlowyStr;
|
use crate::core::flowy_str::OTString;
|
||||||
use crate::core::interval::Interval;
|
use crate::core::interval::Interval;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn flowy_str_code_unit() {
|
fn flowy_str_code_unit() {
|
||||||
let size = FlowyStr::from("👋").utf16_size();
|
let size = OTString::from("👋").utf16_len();
|
||||||
assert_eq!(size, 2);
|
assert_eq!(size, 2);
|
||||||
|
|
||||||
let s: FlowyStr = "👋 \n👋".into();
|
let s: OTString = "👋 \n👋".into();
|
||||||
let output = s.sub_str(Interval::new(0, size)).unwrap();
|
let output = s.sub_str(Interval::new(0, size)).unwrap();
|
||||||
assert_eq!(output, "👋");
|
assert_eq!(output, "👋");
|
||||||
|
|
||||||
@ -248,24 +300,10 @@ mod tests {
|
|||||||
assert_eq!(output, "👋");
|
assert_eq!(output, "👋");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn flowy_str_sub_str_in_chinese() {
|
|
||||||
let s: FlowyStr = "你好\n😁".into();
|
|
||||||
let size = s.utf16_size();
|
|
||||||
assert_eq!(size, 5);
|
|
||||||
|
|
||||||
let output1 = s.sub_str(Interval::new(0, 2)).unwrap();
|
|
||||||
let output2 = s.sub_str(Interval::new(2, 3)).unwrap();
|
|
||||||
let output3 = s.sub_str(Interval::new(3, 5)).unwrap();
|
|
||||||
assert_eq!(output1, "你好");
|
|
||||||
assert_eq!(output2, "\n");
|
|
||||||
assert_eq!(output3, "😁");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn flowy_str_sub_str_in_chinese2() {
|
fn flowy_str_sub_str_in_chinese2() {
|
||||||
let s: FlowyStr = "😁 \n".into();
|
let s: OTString = "😁 \n".into();
|
||||||
let size = s.utf16_size();
|
let size = s.utf16_len();
|
||||||
assert_eq!(size, 4);
|
assert_eq!(size, 4);
|
||||||
|
|
||||||
let output1 = s.sub_str(Interval::new(0, 3)).unwrap();
|
let output1 = s.sub_str(Interval::new(0, 3)).unwrap();
|
||||||
@ -276,27 +314,17 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn flowy_str_sub_str_in_english() {
|
fn flowy_str_sub_str_in_english() {
|
||||||
let s: FlowyStr = "ab".into();
|
let s: OTString = "ab".into();
|
||||||
let size = s.utf16_size();
|
let size = s.utf16_len();
|
||||||
assert_eq!(size, 2);
|
assert_eq!(size, 2);
|
||||||
|
|
||||||
let output = s.sub_str(Interval::new(0, 2)).unwrap();
|
let output = s.sub_str(Interval::new(0, 2)).unwrap();
|
||||||
assert_eq!(output, "ab");
|
assert_eq!(output, "ab");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn flowy_str_utf16_code_point_iter_test1() {
|
|
||||||
let s: FlowyStr = "👋😁👋".into();
|
|
||||||
let mut iter = s.utf16_code_point_iter();
|
|
||||||
assert_eq!(iter.next().unwrap(), "👋".to_string());
|
|
||||||
assert_eq!(iter.next().unwrap(), "😁".to_string());
|
|
||||||
assert_eq!(iter.next().unwrap(), "👋".to_string());
|
|
||||||
assert_eq!(iter.next(), None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn flowy_str_utf16_code_point_iter_test2() {
|
fn flowy_str_utf16_code_point_iter_test2() {
|
||||||
let s: FlowyStr = "👋😁👋".into();
|
let s: OTString = "👋😁👋".into();
|
||||||
let iter = s.utf16_code_point_iter();
|
let iter = s.utf16_code_point_iter();
|
||||||
let result = iter.skip(1).take(1).collect::<String>();
|
let result = iter.skip(1).take(1).collect::<String>();
|
||||||
assert_eq!(result, "😁".to_string());
|
assert_eq!(result, "😁".to_string());
|
||||||
|
@ -1,49 +1,51 @@
|
|||||||
use crate::core::operation::{Attributes, Operation, PhantomAttributes};
|
use crate::core::operation::{Attributes, Operation, PhantomAttributes};
|
||||||
use crate::rich_text::RichTextAttributes;
|
use crate::rich_text::RichTextAttributes;
|
||||||
|
|
||||||
pub type RichTextOpBuilder = OperationBuilder<RichTextAttributes>;
|
pub type RichTextOpBuilder = OperationsBuilder<RichTextAttributes>;
|
||||||
pub type PlainTextOpBuilder = OperationBuilder<PhantomAttributes>;
|
pub type PlainTextOpBuilder = OperationsBuilder<PhantomAttributes>;
|
||||||
|
|
||||||
pub struct OperationBuilder<T: Attributes> {
|
pub struct OperationsBuilder<T: Attributes> {
|
||||||
ty: Operation<T>,
|
operations: Vec<Operation<T>>,
|
||||||
attrs: T,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> OperationBuilder<T>
|
impl<T> OperationsBuilder<T>
|
||||||
where
|
where
|
||||||
T: Attributes,
|
T: Attributes,
|
||||||
{
|
{
|
||||||
pub fn new(ty: Operation<T>) -> OperationBuilder<T> {
|
pub fn new() -> OperationsBuilder<T> {
|
||||||
OperationBuilder {
|
OperationsBuilder { operations: vec![] }
|
||||||
ty,
|
|
||||||
attrs: T::default(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn retain(n: usize) -> OperationBuilder<T> {
|
pub fn retain_with_attributes(mut self, n: usize, attributes: T) -> OperationsBuilder<T> {
|
||||||
OperationBuilder::new(Operation::Retain(n.into()))
|
let retain = Operation::retain_with_attributes(n.into(), attributes);
|
||||||
}
|
self.operations.push(retain);
|
||||||
|
|
||||||
pub fn delete(n: usize) -> OperationBuilder<T> {
|
|
||||||
OperationBuilder::new(Operation::Delete(n))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn insert(s: &str) -> OperationBuilder<T> {
|
|
||||||
OperationBuilder::new(Operation::Insert(s.into()))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn attributes(mut self, attrs: T) -> OperationBuilder<T> {
|
|
||||||
self.attrs = attrs;
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(self) -> Operation<T> {
|
pub fn retain(mut self, n: usize) -> OperationsBuilder<T> {
|
||||||
let mut operation = self.ty;
|
let retain = Operation::retain(n.into());
|
||||||
match &mut operation {
|
self.operations.push(retain);
|
||||||
Operation::Delete(_) => {}
|
self
|
||||||
Operation::Retain(retain) => retain.attributes = self.attrs,
|
|
||||||
Operation::Insert(insert) => insert.attributes = self.attrs,
|
|
||||||
}
|
}
|
||||||
operation
|
|
||||||
|
pub fn delete(mut self, n: usize) -> OperationsBuilder<T> {
|
||||||
|
self.operations.push(Operation::Delete(n));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert_with_attributes(mut self, s: &str, attributes: T) -> OperationsBuilder<T> {
|
||||||
|
let insert = Operation::insert_with_attributes(s.into(), attributes);
|
||||||
|
self.operations.push(insert);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert(mut self, s: &str) -> OperationsBuilder<T> {
|
||||||
|
let insert = Operation::insert(s.into());
|
||||||
|
self.operations.push(insert);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build(self) -> Vec<Operation<T>> {
|
||||||
|
self.operations
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
use crate::core::flowy_str::FlowyStr;
|
use crate::core::flowy_str::OTString;
|
||||||
use crate::core::interval::Interval;
|
use crate::core::interval::Interval;
|
||||||
use crate::core::operation::OperationBuilder;
|
|
||||||
use crate::errors::OTError;
|
use crate::errors::OTError;
|
||||||
use serde::{Deserialize, Serialize, __private::Formatter};
|
use serde::{Deserialize, Serialize, __private::Formatter};
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
@ -11,7 +10,7 @@ use std::{
|
|||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait OperationTransformable {
|
pub trait OperationTransform {
|
||||||
/// Merges the operation with `other` into one operation while preserving
|
/// Merges the operation with `other` into one operation while preserving
|
||||||
/// the changes of both.
|
/// the changes of both.
|
||||||
///
|
///
|
||||||
@ -22,7 +21,7 @@ pub trait OperationTransformable {
|
|||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use lib_ot::core::{OperationTransformable, PlainTextDeltaBuilder};
|
/// use lib_ot::core::{OperationTransform, PlainTextDeltaBuilder};
|
||||||
/// let document = PlainTextDeltaBuilder::new().build();
|
/// let document = PlainTextDeltaBuilder::new().build();
|
||||||
/// let delta = PlainTextDeltaBuilder::new().insert("abc").build();
|
/// let delta = PlainTextDeltaBuilder::new().insert("abc").build();
|
||||||
/// let new_document = document.compose(&delta).unwrap();
|
/// let new_document = document.compose(&delta).unwrap();
|
||||||
@ -51,7 +50,7 @@ pub trait OperationTransformable {
|
|||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use lib_ot::core::{OperationTransformable, PlainTextDeltaBuilder};
|
/// use lib_ot::core::{OperationTransform, PlainTextDeltaBuilder};
|
||||||
/// let original_document = PlainTextDeltaBuilder::new().build();
|
/// let original_document = PlainTextDeltaBuilder::new().build();
|
||||||
/// let delta = PlainTextDeltaBuilder::new().insert("abc").build();
|
/// let delta = PlainTextDeltaBuilder::new().insert("abc").build();
|
||||||
///
|
///
|
||||||
@ -71,7 +70,7 @@ pub trait OperationTransformable {
|
|||||||
/// Because [Operation] is generic over the T, so you must specify the T. For example, the [PlainTextDelta]. It use
|
/// Because [Operation] is generic over the T, so you must specify the T. For example, the [PlainTextDelta]. It use
|
||||||
/// use [PhantomAttributes] as the T. [PhantomAttributes] does nothing, just a phantom.
|
/// use [PhantomAttributes] as the T. [PhantomAttributes] does nothing, just a phantom.
|
||||||
///
|
///
|
||||||
pub trait Attributes: Default + Display + Eq + PartialEq + Clone + Debug + OperationTransformable {
|
pub trait Attributes: Default + Display + Eq + PartialEq + Clone + Debug + OperationTransform {
|
||||||
fn is_empty(&self) -> bool {
|
fn is_empty(&self) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
@ -105,6 +104,40 @@ impl<T> Operation<T>
|
|||||||
where
|
where
|
||||||
T: Attributes,
|
T: Attributes,
|
||||||
{
|
{
|
||||||
|
pub fn delete(n: usize) -> Self {
|
||||||
|
Self::Delete(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a [Retain] operation with the given attributes
|
||||||
|
pub fn retain_with_attributes(n: usize, attributes: T) -> Self {
|
||||||
|
Self::Retain(Retain { n, attributes })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a [Retain] operation without attributes
|
||||||
|
pub fn retain(n: usize) -> Self {
|
||||||
|
Self::Retain(Retain {
|
||||||
|
n,
|
||||||
|
attributes: T::default(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a [Insert] operation with the given attributes
|
||||||
|
pub fn insert_with_attributes(s: &str, attributes: T) -> Self {
|
||||||
|
Self::Insert(Insert {
|
||||||
|
s: OTString::from(s),
|
||||||
|
attributes,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a [Insert] operation without attributes
|
||||||
|
pub fn insert(s: &str) -> Self {
|
||||||
|
Self::Insert(Insert {
|
||||||
|
s: OTString::from(s),
|
||||||
|
attributes: T::default(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the String if the operation is [Insert] operation, otherwise return the empty string.
|
||||||
pub fn get_data(&self) -> &str {
|
pub fn get_data(&self) -> &str {
|
||||||
match self {
|
match self {
|
||||||
Operation::Delete(_) => "",
|
Operation::Delete(_) => "",
|
||||||
@ -152,45 +185,58 @@ where
|
|||||||
let right;
|
let right;
|
||||||
match self {
|
match self {
|
||||||
Operation::Delete(n) => {
|
Operation::Delete(n) => {
|
||||||
left = Some(OperationBuilder::<T>::delete(index).build());
|
left = Some(Operation::<T>::delete(index));
|
||||||
right = Some(OperationBuilder::<T>::delete(*n - index).build());
|
right = Some(Operation::<T>::delete(*n - index));
|
||||||
}
|
}
|
||||||
Operation::Retain(retain) => {
|
Operation::Retain(retain) => {
|
||||||
left = Some(OperationBuilder::<T>::delete(index).build());
|
left = Some(Operation::<T>::delete(index));
|
||||||
right = Some(OperationBuilder::<T>::delete(retain.n - index).build());
|
right = Some(Operation::<T>::delete(retain.n - index));
|
||||||
}
|
}
|
||||||
Operation::Insert(insert) => {
|
Operation::Insert(insert) => {
|
||||||
let attributes = self.get_attributes();
|
let attributes = self.get_attributes();
|
||||||
left = Some(
|
left = Some(Operation::<T>::insert_with_attributes(
|
||||||
OperationBuilder::<T>::insert(&insert.s[0..index])
|
&insert.s[0..index],
|
||||||
.attributes(attributes.clone())
|
attributes.clone(),
|
||||||
.build(),
|
));
|
||||||
);
|
right = Some(Operation::<T>::insert_with_attributes(
|
||||||
right = Some(
|
&insert.s[index..insert.utf16_size()],
|
||||||
OperationBuilder::<T>::insert(&insert.s[index..insert.utf16_size()])
|
attributes,
|
||||||
.attributes(attributes)
|
));
|
||||||
.build(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(left, right)
|
(left, right)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns an operation with the specified width.
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `interval`: Specify the shrink width of the operation.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use lib_ot::core::{Interval, Operation, PhantomAttributes};
|
||||||
|
/// let operation = Operation::<PhantomAttributes>::insert("1234");
|
||||||
|
///
|
||||||
|
/// let op1 = operation.shrink(Interval::new(0,3)).unwrap();
|
||||||
|
/// assert_eq!(op1 , Operation::insert("123"));
|
||||||
|
///
|
||||||
|
/// let op2= operation.shrink(Interval::new(3,4)).unwrap();
|
||||||
|
/// assert_eq!(op2, Operation::insert("4"));
|
||||||
|
/// ```
|
||||||
pub fn shrink(&self, interval: Interval) -> Option<Operation<T>> {
|
pub fn shrink(&self, interval: Interval) -> Option<Operation<T>> {
|
||||||
let op = match self {
|
let op = match self {
|
||||||
Operation::Delete(n) => OperationBuilder::delete(min(*n, interval.size())).build(),
|
Operation::Delete(n) => Operation::delete(min(*n, interval.size())),
|
||||||
Operation::Retain(retain) => OperationBuilder::retain(min(retain.n, interval.size()))
|
Operation::Retain(retain) => {
|
||||||
.attributes(retain.attributes.clone())
|
Operation::retain_with_attributes(min(retain.n, interval.size()), retain.attributes.clone())
|
||||||
.build(),
|
}
|
||||||
Operation::Insert(insert) => {
|
Operation::Insert(insert) => {
|
||||||
if interval.start > insert.utf16_size() {
|
if interval.start > insert.utf16_size() {
|
||||||
OperationBuilder::insert("").build()
|
Operation::insert("")
|
||||||
} else {
|
} else {
|
||||||
let s = insert.s.sub_str(interval).unwrap_or_else(|| "".to_owned());
|
let s = insert.s.sub_str(interval).unwrap_or_else(|| "".to_owned());
|
||||||
OperationBuilder::insert(&s)
|
Operation::insert_with_attributes(&s, insert.attributes.clone())
|
||||||
.attributes(insert.attributes.clone())
|
|
||||||
.build()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -287,7 +333,7 @@ where
|
|||||||
self.n += n;
|
self.n += n;
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(OperationBuilder::retain(n).attributes(attributes).build())
|
Some(Operation::retain_with_attributes(n, attributes))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -330,7 +376,7 @@ where
|
|||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct Insert<T: Attributes> {
|
pub struct Insert<T: Attributes> {
|
||||||
pub s: FlowyStr,
|
pub s: OTString,
|
||||||
pub attributes: T,
|
pub attributes: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -360,7 +406,7 @@ where
|
|||||||
T: Attributes,
|
T: Attributes,
|
||||||
{
|
{
|
||||||
pub fn utf16_size(&self) -> usize {
|
pub fn utf16_size(&self) -> usize {
|
||||||
self.s.utf16_size()
|
self.s.utf16_len()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn merge_or_new_op(&mut self, s: &str, attributes: T) -> Option<Operation<T>> {
|
pub fn merge_or_new_op(&mut self, s: &str, attributes: T) -> Option<Operation<T>> {
|
||||||
@ -368,7 +414,7 @@ where
|
|||||||
self.s += s;
|
self.s += s;
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(OperationBuilder::<T>::insert(s).attributes(attributes).build())
|
Some(Operation::<T>::insert_with_attributes(s, attributes))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -398,11 +444,11 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> std::convert::From<FlowyStr> for Insert<T>
|
impl<T> std::convert::From<OTString> for Insert<T>
|
||||||
where
|
where
|
||||||
T: Attributes,
|
T: Attributes,
|
||||||
{
|
{
|
||||||
fn from(s: FlowyStr) -> Self {
|
fn from(s: OTString) -> Self {
|
||||||
Insert {
|
Insert {
|
||||||
s,
|
s,
|
||||||
attributes: T::default(),
|
attributes: T::default(),
|
||||||
@ -420,7 +466,7 @@ impl fmt::Display for PhantomAttributes {
|
|||||||
|
|
||||||
impl Attributes for PhantomAttributes {}
|
impl Attributes for PhantomAttributes {}
|
||||||
|
|
||||||
impl OperationTransformable for PhantomAttributes {
|
impl OperationTransform for PhantomAttributes {
|
||||||
fn compose(&self, _other: &Self) -> Result<Self, OTError> {
|
fn compose(&self, _other: &Self) -> Result<Self, OTError> {
|
||||||
Ok(self.clone())
|
Ok(self.clone())
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::core::flowy_str::FlowyStr;
|
use crate::core::flowy_str::OTString;
|
||||||
use crate::core::operation::{Attributes, Insert, Operation, Retain};
|
use crate::core::operation::{Attributes, Insert, Operation, Retain};
|
||||||
use serde::{
|
use serde::{
|
||||||
de,
|
de,
|
||||||
@ -249,7 +249,7 @@ where
|
|||||||
where
|
where
|
||||||
A: SeqAccess<'de>,
|
A: SeqAccess<'de>,
|
||||||
{
|
{
|
||||||
let s = match serde::de::SeqAccess::next_element::<FlowyStr>(&mut seq)? {
|
let s = match serde::de::SeqAccess::next_element::<OTString>(&mut seq)? {
|
||||||
Some(val) => val,
|
Some(val) => val,
|
||||||
None => {
|
None => {
|
||||||
return Err(de::Error::invalid_length(0, &"struct Insert with 2 elements"));
|
return Err(de::Error::invalid_length(0, &"struct Insert with 2 elements"));
|
||||||
@ -271,7 +271,7 @@ where
|
|||||||
where
|
where
|
||||||
V: MapAccess<'de>,
|
V: MapAccess<'de>,
|
||||||
{
|
{
|
||||||
let mut s: Option<FlowyStr> = None;
|
let mut s: Option<OTString> = None;
|
||||||
let mut attributes: Option<T> = None;
|
let mut attributes: Option<T> = None;
|
||||||
while let Some(key) = map.next_key()? {
|
while let Some(key) = map.next_key()? {
|
||||||
match key {
|
match key {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
use crate::core::{Attributes, Operation, OperationTransformable};
|
use crate::core::{Attributes, Operation, OperationTransform};
|
||||||
use crate::{block_attribute, errors::OTError, ignore_attribute, inline_attribute, list_attribute};
|
use crate::{block_attribute, errors::OTError, ignore_attribute, inline_attribute, list_attribute};
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use std::{
|
use std::{
|
||||||
@ -122,7 +122,7 @@ impl Attributes for RichTextAttributes {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OperationTransformable for RichTextAttributes {
|
impl OperationTransform for RichTextAttributes {
|
||||||
fn compose(&self, other: &Self) -> Result<Self, OTError>
|
fn compose(&self, other: &Self) -> Result<Self, OTError>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
|
Loading…
Reference in New Issue
Block a user