Browse Source

preserve line format on split

appflowy 3 years ago
parent
commit
4d3eabb761

+ 1 - 1
app_flowy/packages/flowy_editor/lib/src/model/heuristic/rule.dart

@@ -47,7 +47,7 @@ class Rules {
     // const ForceNewlineForInsertsAroundEmbedRule(),
     const AutoExitBlockRule(),
     const PreserveBlockStyleOnInsertRule(),
-    // const PreserveLineStyleOnSplitRule(),
+    const PreserveLineStyleOnSplitRule(),
     const ResetLineFormatOnNewLineRule(),
     const AutoFormatLinksRule(),
     const PreserveInlineStylesRule(),

+ 1 - 1
rust-lib/flowy-ot/src/client/extensions/format/format_at_position.rs

@@ -6,7 +6,7 @@ use crate::{
 pub struct FormatLinkAtCaretPositionExt {}
 
 impl FormatExt for FormatLinkAtCaretPositionExt {
-    fn ext_name(&self) -> &str { "FormatLinkAtCaretPositionExt" }
+    fn ext_name(&self) -> &str { std::any::type_name::<FormatLinkAtCaretPositionExt>() }
 
     fn apply(&self, delta: &Delta, interval: Interval, attribute: &Attribute) -> Option<Delta> {
         if attribute.key != AttributeKey::Link || interval.size() != 0 {

+ 3 - 3
rust-lib/flowy-ot/src/client/extensions/format/resolve_block_format.rs

@@ -15,9 +15,9 @@ use crate::{
     },
 };
 
-pub struct ResolveBlockFormatExt {}
-impl FormatExt for ResolveBlockFormatExt {
-    fn ext_name(&self) -> &str { "ResolveBlockFormatExt" }
+pub struct ResolveBlockFormat {}
+impl FormatExt for ResolveBlockFormat {
+    fn ext_name(&self) -> &str { std::any::type_name::<ResolveBlockFormat>() }
 
     fn apply(&self, delta: &Delta, interval: Interval, attribute: &Attribute) -> Option<Delta> {
         if attribute.scope != AttributeScope::Block {

+ 3 - 3
rust-lib/flowy-ot/src/client/extensions/format/resolve_inline_format.rs

@@ -6,9 +6,9 @@ use crate::{
     core::{Attribute, AttributeScope, CharMetric, Delta, DeltaBuilder, DeltaIter, Interval},
 };
 
-pub struct ResolveInlineFormatExt {}
-impl FormatExt for ResolveInlineFormatExt {
-    fn ext_name(&self) -> &str { "ResolveInlineFormatExt" }
+pub struct ResolveInlineFormat {}
+impl FormatExt for ResolveInlineFormat {
+    fn ext_name(&self) -> &str { std::any::type_name::<ResolveInlineFormat>() }
 
     fn apply(&self, delta: &Delta, interval: Interval, attribute: &Attribute) -> Option<Delta> {
         if attribute.scope != AttributeScope::Inline {

+ 3 - 3
rust-lib/flowy-ot/src/client/extensions/insert/auto_exit_block.rs

@@ -14,10 +14,10 @@ use crate::{
 
 use crate::core::{attributes_except_header, is_empty_line_at_index};
 
-pub struct AutoExitBlockExt {}
+pub struct AutoExitBlock {}
 
-impl InsertExt for AutoExitBlockExt {
-    fn ext_name(&self) -> &str { "AutoExitBlockExt" }
+impl InsertExt for AutoExitBlock {
+    fn ext_name(&self) -> &str { std::any::type_name::<AutoExitBlock>() }
 
     fn apply(&self, delta: &Delta, replace_len: usize, text: &str, index: usize) -> Option<Delta> {
         // Auto exit block will be triggered by enter two new lines

+ 1 - 1
rust-lib/flowy-ot/src/client/extensions/insert/auto_format.rs

@@ -5,7 +5,7 @@ use crate::{
 
 pub struct AutoFormatExt {}
 impl InsertExt for AutoFormatExt {
-    fn ext_name(&self) -> &str { "AutoFormatExt" }
+    fn ext_name(&self) -> &str { std::any::type_name::<AutoFormatExt>() }
 
     fn apply(&self, delta: &Delta, replace_len: usize, text: &str, index: usize) -> Option<Delta> {
         // enter whitespace to trigger auto format

+ 3 - 3
rust-lib/flowy-ot/src/client/extensions/insert/default_insert.rs

@@ -3,9 +3,9 @@ use crate::{
     core::{AttributeKey, Attributes, Delta, DeltaBuilder, DeltaIter, NEW_LINE},
 };
 
-pub struct DefaultInsertExt {}
-impl InsertExt for DefaultInsertExt {
-    fn ext_name(&self) -> &str { "DefaultInsertExt" }
+pub struct DefaultInsertAttribute {}
+impl InsertExt for DefaultInsertAttribute {
+    fn ext_name(&self) -> &str { std::any::type_name::<DefaultInsertAttribute>() }
 
     fn apply(&self, delta: &Delta, replace_len: usize, text: &str, index: usize) -> Option<Delta> {
         let iter = DeltaIter::new(delta);

+ 4 - 19
rust-lib/flowy-ot/src/client/extensions/insert/mod.rs

@@ -1,34 +1,19 @@
 pub use auto_exit_block::*;
 pub use auto_format::*;
 pub use default_insert::*;
-pub use preserve_block_style::*;
-pub use preserve_inline_style::*;
+pub use preserve_block_format::*;
+pub use preserve_inline_format::*;
 pub use reset_format_on_new_line::*;
 
 mod auto_exit_block;
 mod auto_format;
 mod default_insert;
-mod preserve_block_style;
-mod preserve_inline_style;
+mod preserve_block_format;
+mod preserve_inline_format;
 mod reset_format_on_new_line;
 
 use crate::{client::extensions::InsertExt, core::Delta};
 
-pub struct PreserveLineStyleOnSplitExt {}
-impl InsertExt for PreserveLineStyleOnSplitExt {
-    fn ext_name(&self) -> &str { "PreserveLineStyleOnSplitExt" }
-
-    fn apply(
-        &self,
-        _delta: &Delta,
-        _replace_len: usize,
-        _text: &str,
-        _index: usize,
-    ) -> Option<Delta> {
-        None
-    }
-}
-
 pub struct InsertEmbedsExt {}
 impl InsertExt for InsertEmbedsExt {
     fn ext_name(&self) -> &str { "InsertEmbedsExt" }

+ 3 - 6
rust-lib/flowy-ot/src/client/extensions/insert/preserve_block_style.rs → rust-lib/flowy-ot/src/client/extensions/insert/preserve_block_format.rs

@@ -13,9 +13,9 @@ use crate::{
     },
 };
 
-pub struct PreserveBlockStyleOnInsertExt {}
-impl InsertExt for PreserveBlockStyleOnInsertExt {
-    fn ext_name(&self) -> &str { "PreserveBlockStyleOnInsertExt" }
+pub struct PreserveBlockFormatOnInsert {}
+impl InsertExt for PreserveBlockFormatOnInsert {
+    fn ext_name(&self) -> &str { std::any::type_name::<PreserveBlockFormatOnInsert>() }
 
     fn apply(&self, delta: &Delta, replace_len: usize, text: &str, index: usize) -> Option<Delta> {
         if !is_newline(text) {
@@ -38,7 +38,6 @@ impl InsertExt for PreserveBlockStyleOnInsertExt {
                 }
 
                 let lines: Vec<_> = text.split(NEW_LINE).collect();
-                let line_count = lines.len();
                 let mut new_delta = DeltaBuilder::new().retain(index + replace_len).build();
                 lines.iter().enumerate().for_each(|(i, line)| {
                     if !line.is_empty() {
@@ -52,8 +51,6 @@ impl InsertExt for PreserveBlockStyleOnInsertExt {
                     } else {
                         // do nothing
                     }
-
-                    log::info!("{}", new_delta);
                 });
                 if !reset_attribute.is_empty() {
                     new_delta.retain(offset, Attributes::empty());

+ 101 - 0
rust-lib/flowy-ot/src/client/extensions/insert/preserve_inline_format.rs

@@ -0,0 +1,101 @@
+use crate::{
+    client::{
+        extensions::InsertExt,
+        util::{contain_newline, is_newline},
+    },
+    core::{
+        AttributeKey,
+        Attributes,
+        Delta,
+        DeltaBuilder,
+        DeltaIter,
+        OpNewline,
+        Operation,
+        NEW_LINE,
+    },
+};
+
+pub struct PreserveInlineFormat {}
+impl InsertExt for PreserveInlineFormat {
+    fn ext_name(&self) -> &str { std::any::type_name::<PreserveInlineFormat>() }
+
+    fn apply(&self, delta: &Delta, replace_len: usize, text: &str, index: usize) -> Option<Delta> {
+        if contain_newline(text) {
+            return None;
+        }
+
+        let mut iter = DeltaIter::new(delta);
+        let prev = iter.last_op_before_index(index)?;
+        if OpNewline::parse(&prev).is_contain() {
+            return None;
+        }
+
+        let mut attributes = prev.get_attributes();
+        if attributes.is_empty() || !attributes.contains_key(&AttributeKey::Link) {
+            return Some(
+                DeltaBuilder::new()
+                    .retain(index + replace_len)
+                    .insert_with_attributes(text, attributes)
+                    .build(),
+            );
+        }
+
+        let next = iter.next_op();
+        match &next {
+            None => attributes = Attributes::empty(),
+            Some(next) => {
+                if OpNewline::parse(&next).is_equal() {
+                    attributes = Attributes::empty();
+                }
+            },
+        }
+
+        let new_delta = DeltaBuilder::new()
+            .retain(index + replace_len)
+            .insert_with_attributes(text, attributes)
+            .build();
+
+        return Some(new_delta);
+    }
+}
+
+pub struct PreserveLineFormatOnSplit {}
+impl InsertExt for PreserveLineFormatOnSplit {
+    fn ext_name(&self) -> &str { std::any::type_name::<PreserveLineFormatOnSplit>() }
+
+    fn apply(&self, delta: &Delta, replace_len: usize, text: &str, index: usize) -> Option<Delta> {
+        if !is_newline(text) {
+            return None;
+        }
+
+        let mut iter = DeltaIter::new(delta);
+        let prev = iter.last_op_before_index(index)?;
+        if OpNewline::parse(&prev).is_end() {
+            return None;
+        }
+
+        let next = iter.next_op()?;
+        let newline_status = OpNewline::parse(&next);
+        if newline_status.is_end() {
+            return None;
+        }
+
+        let mut new_delta = Delta::new();
+        new_delta.retain(index + replace_len, Attributes::empty());
+
+        if newline_status.is_contain() {
+            debug_assert!(next.has_attribute() == false);
+            new_delta.insert(NEW_LINE, Attributes::empty());
+            return Some(new_delta);
+        }
+
+        match iter.first_newline_op() {
+            None => {},
+            Some((newline_op, _)) => {
+                new_delta.insert(NEW_LINE, newline_op.get_attributes());
+            },
+        }
+
+        Some(new_delta)
+    }
+}

+ 0 - 48
rust-lib/flowy-ot/src/client/extensions/insert/preserve_inline_style.rs

@@ -1,48 +0,0 @@
-use crate::{
-    client::{extensions::InsertExt, util::contain_newline},
-    core::{AttributeKey, Attributes, Delta, DeltaBuilder, DeltaIter, OpNewline},
-};
-
-pub struct PreserveInlineStylesExt {}
-impl InsertExt for PreserveInlineStylesExt {
-    fn ext_name(&self) -> &str { "PreserveInlineStylesExt" }
-
-    fn apply(&self, delta: &Delta, replace_len: usize, text: &str, index: usize) -> Option<Delta> {
-        if contain_newline(text) {
-            return None;
-        }
-
-        let mut iter = DeltaIter::new(delta);
-        let prev = iter.last_op_before_index(index)?;
-        if OpNewline::parse(&prev).is_contain() {
-            return None;
-        }
-
-        let mut attributes = prev.get_attributes();
-        if attributes.is_empty() || !attributes.contains_key(&AttributeKey::Link) {
-            return Some(
-                DeltaBuilder::new()
-                    .retain(index + replace_len)
-                    .insert_with_attributes(text, attributes)
-                    .build(),
-            );
-        }
-
-        let next = iter.next_op();
-        match &next {
-            None => attributes = Attributes::empty(),
-            Some(next) => {
-                if OpNewline::parse(&next).is_equal() {
-                    attributes = Attributes::empty();
-                }
-            },
-        }
-
-        let new_delta = DeltaBuilder::new()
-            .retain(index + replace_len)
-            .insert_with_attributes(text, attributes)
-            .build();
-
-        return Some(new_delta);
-    }
-}

+ 3 - 3
rust-lib/flowy-ot/src/client/extensions/insert/reset_format_on_new_line.rs

@@ -3,9 +3,9 @@ use crate::{
     core::{AttributeKey, Attributes, CharMetric, Delta, DeltaBuilder, DeltaIter, NEW_LINE},
 };
 
-pub struct ResetLineFormatOnNewLineExt {}
-impl InsertExt for ResetLineFormatOnNewLineExt {
-    fn ext_name(&self) -> &str { "ResetLineFormatOnNewLineExt" }
+pub struct ResetLineFormatOnNewLine {}
+impl InsertExt for ResetLineFormatOnNewLine {
+    fn ext_name(&self) -> &str { std::any::type_name::<ResetLineFormatOnNewLine>() }
 
     fn apply(&self, delta: &Delta, replace_len: usize, text: &str, index: usize) -> Option<Delta> {
         if !is_newline(text) {

+ 8 - 8
rust-lib/flowy-ot/src/client/view.rs

@@ -82,21 +82,21 @@ fn construct_insert_exts() -> Vec<InsertExtension> {
     vec![
         Box::new(InsertEmbedsExt {}),
         Box::new(ForceNewlineForInsertsAroundEmbedExt {}),
-        Box::new(AutoExitBlockExt {}),
-        Box::new(PreserveBlockStyleOnInsertExt {}),
-        Box::new(PreserveLineStyleOnSplitExt {}),
-        Box::new(ResetLineFormatOnNewLineExt {}),
+        Box::new(AutoExitBlock {}),
+        Box::new(PreserveBlockFormatOnInsert {}),
+        Box::new(PreserveLineFormatOnSplit {}),
+        Box::new(ResetLineFormatOnNewLine {}),
         Box::new(AutoFormatExt {}),
-        Box::new(PreserveInlineStylesExt {}),
-        Box::new(DefaultInsertExt {}),
+        Box::new(PreserveInlineFormat {}),
+        Box::new(DefaultInsertAttribute {}),
     ]
 }
 
 fn construct_format_exts() -> Vec<FormatExtension> {
     vec![
         Box::new(FormatLinkAtCaretPositionExt {}),
-        Box::new(ResolveBlockFormatExt {}),
-        Box::new(ResolveInlineFormatExt {}),
+        Box::new(ResolveBlockFormat {}),
+        Box::new(ResolveInlineFormat {}),
     ]
 }
 

+ 30 - 27
rust-lib/flowy-ot/src/core/delta/cursor.rs

@@ -8,9 +8,9 @@ use std::{cmp::min, iter::Enumerate, slice::Iter};
 pub struct Cursor<'a> {
     pub(crate) delta: &'a Delta,
     pub(crate) origin_iv: Interval,
-    pub(crate) next_iv: Interval,
-    pub(crate) cur_char_count: usize,
-    pub(crate) cur_op_index: usize,
+    pub(crate) consume_iv: Interval,
+    pub(crate) consume_count: usize,
+    pub(crate) op_index: usize,
     iter: Enumerate<Iter<'a, Operation>>,
     next_op: Option<Operation>,
 }
@@ -21,9 +21,9 @@ impl<'a> Cursor<'a> {
         let mut cursor = Self {
             delta,
             origin_iv: interval,
-            next_iv: interval,
-            cur_char_count: 0,
-            cur_op_index: 0,
+            consume_iv: interval,
+            consume_count: 0,
+            op_index: 0,
             iter: delta.ops.iter().enumerate(),
             next_op: None,
         };
@@ -39,14 +39,14 @@ impl<'a> Cursor<'a> {
     // get the last operation before the index
     pub fn last_op_before_index(&mut self, index: Option<usize>) -> Option<Operation> {
         let mut find_op = None;
-        let next_op = self.next_op.take();
-        let mut next_op = next_op.as_ref();
+        let holder = self.next_op.clone();
+        let mut next_op = holder.as_ref();
 
         if next_op.is_none() {
             next_op = find_next_op(self);
         }
 
-        let pre_char_count = self.cur_char_count;
+        let mut pos = 0;
         while find_op.is_none() && next_op.is_some() {
             let op = next_op.take().unwrap();
             let interval = self.next_iv_before(index);
@@ -56,13 +56,16 @@ impl<'a> Cursor<'a> {
             }
 
             find_op = op.shrink(interval);
+            self.next_op = None;
+
             let suffix = Interval::new(0, op.len()).suffix(interval);
             if !suffix.is_empty() {
                 self.next_op = op.shrink(suffix);
             }
 
-            self.cur_char_count += interval.end;
-            self.next_iv.start = self.cur_char_count;
+            pos += interval.end;
+            self.consume_count += interval.end;
+            self.consume_iv.start = self.consume_count;
 
             if find_op.is_none() {
                 next_op = find_next_op(self);
@@ -71,9 +74,8 @@ impl<'a> Cursor<'a> {
 
         if find_op.is_some() && index.is_some() {
             // try to find the next op before the index if iter_char_count less than index
-            let pos = self.cur_char_count - pre_char_count;
             let end = index.unwrap();
-            if end > pos {
+            if end > pos && self.has_next() {
                 return self.last_op_before_index(Some(end - pos));
             }
         }
@@ -83,18 +85,18 @@ impl<'a> Cursor<'a> {
     pub fn has_next(&self) -> bool { self.next_iter_op().is_some() }
 
     fn descend(&mut self, index: usize) {
-        self.next_iv.start += index;
+        self.consume_iv.start += index;
 
-        if self.cur_char_count >= self.next_iv.start {
+        if self.consume_count >= self.consume_iv.start {
             return;
         }
         while let Some((o_index, op)) = self.iter.next() {
-            self.cur_op_index = o_index;
-            let start = self.cur_char_count;
+            self.op_index = o_index;
+            let start = self.consume_count;
             let end = start + op.len();
-            let intersect = Interval::new(start, end).intersect(self.next_iv);
+            let intersect = Interval::new(start, end).intersect(self.consume_iv);
             if intersect.is_empty() {
-                self.cur_char_count += op.len();
+                self.consume_count += op.len();
             } else {
                 self.next_op = Some(op.clone());
                 break;
@@ -108,7 +110,7 @@ impl<'a> Cursor<'a> {
             let mut offset = 0;
             for op in &self.delta.ops {
                 offset += op.len();
-                if offset > self.cur_char_count {
+                if offset > self.consume_count {
                     next_op = Some(op);
                     break;
                 }
@@ -124,12 +126,13 @@ impl<'a> Cursor<'a> {
         }
 
         let op = next_op.unwrap();
-        let start = self.cur_char_count;
+        let start = self.consume_count;
         let end = match index {
-            None => self.cur_char_count + op.len(),
-            Some(index) => self.cur_char_count + min(index, op.len()),
+            None => self.consume_count + op.len(),
+            Some(index) => self.consume_count + min(index, op.len()),
         };
-        let intersect = Interval::new(start, end).intersect(self.next_iv);
+
+        let intersect = Interval::new(start, end).intersect(self.consume_iv);
         let interval = intersect.translate_neg(start);
         interval
     }
@@ -139,7 +142,7 @@ fn find_next_op<'a>(cursor: &mut Cursor<'a>) -> Option<&'a Operation> {
     match cursor.iter.next() {
         None => None,
         Some((o_index, op)) => {
-            cursor.cur_op_index = o_index;
+            cursor.op_index = o_index;
             Some(op)
         },
     }
@@ -154,7 +157,7 @@ pub struct OpMetric {}
 
 impl Metric for OpMetric {
     fn seek(cursor: &mut Cursor, index: usize) -> SeekResult {
-        let _ = check_bound(cursor.cur_op_index, index)?;
+        let _ = check_bound(cursor.op_index, index)?;
         let mut seek_cursor = Cursor::new(cursor.delta, cursor.origin_iv);
         let mut offset = 0;
         while let Some((_, op)) = seek_cursor.iter.next() {
@@ -172,7 +175,7 @@ pub struct CharMetric {}
 
 impl Metric for CharMetric {
     fn seek(cursor: &mut Cursor, index: usize) -> SeekResult {
-        let _ = check_bound(cursor.cur_char_count, index)?;
+        let _ = check_bound(cursor.consume_count, index)?;
         let _ = cursor.last_op_before_index(Some(index));
 
         Ok(())