diff --git a/rust-lib/flowy-ot/src/client/document.rs b/rust-lib/flowy-ot/src/client/document.rs index 640f5eb007..869255c957 100644 --- a/rust-lib/flowy-ot/src/client/document.rs +++ b/rust-lib/flowy-ot/src/client/document.rs @@ -47,6 +47,8 @@ impl Document { pub fn format(&mut self, interval: Interval, attribute: Attribute) -> Result<(), OTError> { log::debug!("format with {} at {}", attribute, interval); + // let format_delta = self.view.format(&self.delta, attribute, interval)?; + self.update_with_attribute(attribute, interval) } diff --git a/rust-lib/flowy-ot/src/client/view/format_ext.rs b/rust-lib/flowy-ot/src/client/view/format_ext.rs index bbbd786418..241e2ecc89 100644 --- a/rust-lib/flowy-ot/src/client/view/format_ext.rs +++ b/rust-lib/flowy-ot/src/client/view/format_ext.rs @@ -1,13 +1,43 @@ use crate::{ client::view::FormatExt, - core::{Attribute, Delta, Interval}, + core::{Attribute, AttributeScope, Attributes, Delta, DeltaBuilder, DeltaIter, Interval}, }; pub struct FormatLinkAtCaretPositionExt {} impl FormatExt for FormatLinkAtCaretPositionExt { fn apply(&self, delta: &Delta, interval: Interval, attribute: &Attribute) -> Option { - unimplemented!() + let mut iter = DeltaIter::new(delta); + iter.seek(interval.start); + let (before, after) = (iter.next(), iter.next()); + let mut start = interval.start; + let mut retain = 0; + + if let Some(before) = before { + if before.contain_attribute(attribute) { + start -= before.length(); + retain += before.length(); + } + } + + if let Some(after) = after { + if after.contain_attribute(attribute) { + if retain != 0 { + retain += after.length(); + } + } + } + + if retain == 0 { + return None; + } + + Some( + DeltaBuilder::new() + .retain(start, Attributes::default()) + .retain(retain, (attribute.clone()).into()) + .build(), + ) } } @@ -15,7 +45,17 @@ pub struct ResolveLineFormatExt {} impl FormatExt for ResolveLineFormatExt { fn apply(&self, delta: &Delta, interval: Interval, attribute: &Attribute) -> Option { - unimplemented!() + if attribute.scope != AttributeScope::Block { + return None; + } + + let mut new_delta = Delta::new(); + new_delta.retain(interval.start, Attributes::default()); + + let mut iter = DeltaIter::new(delta); + iter.seek(interval.start); + + None } } diff --git a/rust-lib/flowy-ot/src/client/view/insert_ext.rs b/rust-lib/flowy-ot/src/client/view/insert_ext.rs index 78fac0c6b7..17fbdacd42 100644 --- a/rust-lib/flowy-ot/src/client/view/insert_ext.rs +++ b/rust-lib/flowy-ot/src/client/view/insert_ext.rs @@ -44,7 +44,7 @@ impl InsertExt for ResetLineFormatOnNewLineExt { } let mut iter = DeltaIter::new(delta); - iter.seek_to(index); + iter.seek(index); let maybe_next_op = iter.next(); if maybe_next_op.is_none() { return None; diff --git a/rust-lib/flowy-ot/src/core/attributes/builder.rs b/rust-lib/flowy-ot/src/core/attributes/builder.rs index 2d94f94431..e97328c745 100644 --- a/rust-lib/flowy-ot/src/core/attributes/builder.rs +++ b/rust-lib/flowy-ot/src/core/attributes/builder.rs @@ -71,7 +71,7 @@ pub enum AttributeKey { UnChecked, } -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq, Clone)] pub enum AttributeScope { Inline, Block, @@ -79,7 +79,7 @@ pub enum AttributeScope { Ignore, } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Attribute { pub key: AttributeKey, pub value: String, @@ -93,6 +93,14 @@ impl fmt::Display for Attribute { } } +impl std::convert::Into for Attribute { + fn into(self) -> Attributes { + let mut attributes = Attributes::new(); + attributes.add(self); + attributes + } +} + pub struct AttrsBuilder { inner: Attributes, } diff --git a/rust-lib/flowy-ot/src/core/delta/cursor.rs b/rust-lib/flowy-ot/src/core/delta/cursor.rs index d1f0c6dd75..5aadfc7451 100644 --- a/rust-lib/flowy-ot/src/core/delta/cursor.rs +++ b/rust-lib/flowy-ot/src/core/delta/cursor.rs @@ -8,8 +8,9 @@ pub struct Cursor<'a> { delta: &'a Delta, interval: Interval, iterator: Iter<'a, Operation>, - offset: usize, - offset_op: Option<&'a Operation>, + char_index: usize, + op_index: usize, + current_op: Option<&'a Operation>, } impl<'a> Cursor<'a> { @@ -18,29 +19,31 @@ impl<'a> Cursor<'a> { delta, interval, iterator: delta.ops.iter(), - offset: 0, - offset_op: None, + char_index: 0, + op_index: 0, + current_op: None, }; cursor } pub fn next_op(&mut self) -> Option { - let mut next_op = self.offset_op.take(); - + let mut next_op = self.current_op.take(); if next_op.is_none() { next_op = self.iterator.next(); } let mut find_op = None; while find_op.is_none() && next_op.is_some() { + self.op_index += 1; + let op = next_op.unwrap(); - if self.offset < self.interval.start { - let intersect = - Interval::new(self.offset, self.offset + op.length()).intersect(self.interval); + if self.char_index < self.interval.start { + let intersect = Interval::new(self.char_index, self.char_index + op.length()) + .intersect(self.interval); if intersect.is_empty() { - self.offset += op.length(); + self.char_index += op.length(); } else { - if let Some(new_op) = op.shrink(intersect.translate_neg(self.offset)) { + if let Some(new_op) = op.shrink(intersect.translate_neg(self.char_index)) { // shrink the op to fit the intersect range // ┌──────────────┐ // │ 1 2 3 4 5 6 │ @@ -50,11 +53,11 @@ impl<'a> Cursor<'a> { // op = "45" find_op = Some(new_op); } - self.offset = intersect.end; + self.char_index = intersect.end; } } else { // the interval passed in the shrink function is base on the op not the delta. - if let Some(new_op) = op.shrink(self.interval.translate_neg(self.offset)) { + if let Some(new_op) = op.shrink(self.interval.translate_neg(self.char_index)) { find_op = Some(new_op); } // for example: extract the ops from three insert ops with interval [2,5). the @@ -67,43 +70,96 @@ impl<'a> Cursor<'a> { // └──────┘ └─▲────┘ └───▲──┘ // │ [2, 5) │ // - self.offset += min(self.interval.size(), op.length()); + self.char_index += min(self.interval.size(), op.length()); } match find_op { None => next_op = self.iterator.next(), - Some(_) => self.interval.start = self.offset, + Some(_) => self.interval.start = self.char_index, } } find_op } - pub fn seek_to(&mut self, index: usize) -> Result<(), OTError> { - if self.offset > index { - let msg = format!( - "{} should be greater than current offset: {}", - index, self.offset - ); - return Err(ErrorBuilder::new(OTErrorCode::IncompatibleLength) - .msg(&msg) - .build()); - } + pub fn seek(&mut self, index: usize) -> Result<(), OTError> { + self.current_op = M::seek(self, index)?; + Ok(()) + } +} - let mut offset = 0; - while let Some(op) = self.iterator.next() { - if offset != 0 { - self.offset = offset; +pub trait Metric { + fn seek<'a, 'b>( + cursor: &'b mut Cursor<'a>, + index: usize, + ) -> Result, OTError>; +} + +pub struct OpMetric {} + +impl Metric for OpMetric { + fn seek<'a, 'b>( + cursor: &'b mut Cursor<'a>, + index: usize, + ) -> Result, OTError> { + let _ = check_bound(cursor.op_index, index)?; + + let mut offset = cursor.op_index; + let mut op_at_index = None; + + while let Some(op) = cursor.iterator.next() { + if offset != cursor.op_index { + cursor.char_index += op.length(); + cursor.op_index = offset; } - offset += op.length(); - self.offset_op = Some(op); + offset += 1; + op_at_index = Some(op); if offset >= index { break; } } - Ok(()) + Ok(op_at_index) } } + +pub struct CharMetric {} + +impl Metric for CharMetric { + fn seek<'a, 'b>( + cursor: &'b mut Cursor<'a>, + index: usize, + ) -> Result, OTError> { + let _ = check_bound(cursor.char_index, index)?; + + let mut offset = cursor.char_index; + let mut op_at_index = None; + while let Some(op) = cursor.iterator.next() { + if offset != cursor.char_index { + cursor.char_index = offset; + cursor.op_index += 1; + } + + offset += op.length(); + op_at_index = Some(op); + + if offset >= index { + break; + } + } + + Ok(op_at_index) + } +} + +fn check_bound(current: usize, target: usize) -> Result<(), OTError> { + if current > target { + let msg = format!("{} should be greater than current: {}", target, current); + return Err(ErrorBuilder::new(OTErrorCode::IncompatibleLength) + .msg(&msg) + .build()); + } + Ok(()) +} diff --git a/rust-lib/flowy-ot/src/core/delta/iterator.rs b/rust-lib/flowy-ot/src/core/delta/iterator.rs index a72a3ce882..f0c65c5eae 100644 --- a/rust-lib/flowy-ot/src/core/delta/iterator.rs +++ b/rust-lib/flowy-ot/src/core/delta/iterator.rs @@ -23,8 +23,8 @@ impl<'a> DeltaIter<'a> { pub fn ops(&mut self) -> Vec { self.collect::>() } - pub fn seek_to(&mut self, n_char: usize) -> Result<(), OTError> { - let _ = self.cursor.seek_to(n_char)?; + pub fn seek(&mut self, n_char: usize) -> Result<(), OTError> { + let _ = self.cursor.seek::(n_char)?; Ok(()) } } @@ -102,7 +102,7 @@ impl<'a> Iterator for AttributesIter<'a> { pub(crate) fn attributes_at_index(delta: &Delta, index: usize) -> Attributes { let mut iter = AttributesIter::new(delta); - iter.seek_to(index); + iter.seek(index); match iter.next() { // None => Attributes::Follow, None => Attributes::new(), diff --git a/rust-lib/flowy-ot/src/core/operation/operation.rs b/rust-lib/flowy-ot/src/core/operation/operation.rs index 7de196f991..b200060f38 100644 --- a/rust-lib/flowy-ot/src/core/operation/operation.rs +++ b/rust-lib/flowy-ot/src/core/operation/operation.rs @@ -1,4 +1,4 @@ -use crate::core::{Attributes, Builder, Interval}; +use crate::core::{Attribute, Attributes, Builder, Interval}; use bytecount::num_chars; use serde::__private::Formatter; use std::{ @@ -48,6 +48,10 @@ impl Operation { pub fn has_attribute(&self) -> bool { !self.get_attributes().is_empty() } + pub fn contain_attribute(&self, attribute: &Attribute) -> bool { + self.get_attributes().contains_key(&attribute.key) + } + pub fn length(&self) -> usize { match self { Operation::Delete(n) => *n,