Browse Source

Try to fix quill-editor load document error. Because Document can only contain insert operations

appflowy 3 years ago
parent
commit
85ad90fc51

+ 4 - 2
frontend/rust-lib/flowy-document/src/core/revision/manager.rs

@@ -15,7 +15,7 @@ use flowy_error::FlowyResult;
 use futures_util::{future, stream, stream::StreamExt};
 use lib_infra::future::FutureResult;
 use lib_ot::{
-    core::{Operation, OperationTransformable},
+    core::{trim, Operation, OperationTransformable},
     errors::OTError,
     rich_text::RichTextDelta,
 };
@@ -259,11 +259,13 @@ fn mk_doc_from_revisions(doc_id: &str, revisions: Vec<Revision>) -> FlowyResult<
         base_rev_id,
     })
 }
+
 fn correct_delta_if_need(delta: &mut RichTextDelta) {
+    trim(delta);
+
     if delta.ops.last().is_none() {
         return;
     }
-
     let data = delta.ops.last().as_ref().unwrap().get_data();
     if !data.ends_with('\n') {
         log::error!("❌The op must end with newline. Correcting it by inserting newline op");

+ 9 - 27
shared-lib/flowy-collaboration/src/document/document.rs

@@ -1,10 +1,3 @@
-use tokio::sync::mpsc;
-
-use lib_ot::{
-    core::*,
-    rich_text::{RichTextAttribute, RichTextDelta},
-};
-
 use crate::{
     document::{
         default::initial_delta,
@@ -13,6 +6,11 @@ use crate::{
     },
     errors::CollaborateError,
 };
+use lib_ot::{
+    core::*,
+    rich_text::{RichTextAttribute, RichTextDelta},
+};
+use tokio::sync::mpsc;
 
 pub trait InitialDocumentText {
     fn initial_delta() -> RichTextDelta;
@@ -81,12 +79,10 @@ impl Document {
         }
     }
 
-    pub fn compose_delta(&mut self, mut delta: RichTextDelta) -> Result<(), CollaborateError> {
+    pub fn compose_delta(&mut self, delta: RichTextDelta) -> Result<(), CollaborateError> {
         tracing::trace!("👉 receive change: {}", delta);
-
-        trim(&mut delta);
         tracing::trace!("{} compose {}", &self.delta.to_json(), delta.to_json());
-        let mut composed_delta = self.delta.compose(&delta)?;
+        let composed_delta = self.delta.compose(&delta)?;
         let mut undo_delta = delta.invert(&self.delta);
 
         let now = chrono::Utc::now().timestamp_millis() as usize;
@@ -107,7 +103,6 @@ impl Document {
         }
 
         tracing::trace!("compose result: {}", composed_delta.to_json());
-        trim(&mut composed_delta);
 
         self.set_delta(composed_delta);
         Ok(())
@@ -171,11 +166,9 @@ impl Document {
             None => Err(CollaborateError::undo().context("Undo stack is empty")),
             Some(undo_delta) => {
                 let (new_delta, inverted_delta) = self.invert(&undo_delta)?;
-                let result = UndoResult::success(new_delta.target_len as usize);
                 self.set_delta(new_delta);
                 self.history.add_redo(inverted_delta);
-
-                Ok(result)
+                Ok(UndoResult { delta: undo_delta })
             },
         }
     }
@@ -185,11 +178,9 @@ impl Document {
             None => Err(CollaborateError::redo()),
             Some(redo_delta) => {
                 let (new_delta, inverted_delta) = self.invert(&redo_delta)?;
-                let result = UndoResult::success(new_delta.target_len as usize);
                 self.set_delta(new_delta);
-
                 self.history.add_undo(inverted_delta);
-                Ok(result)
+                Ok(UndoResult { delta: redo_delta })
             },
         }
     }
@@ -216,12 +207,3 @@ fn validate_interval(delta: &RichTextDelta, interval: &Interval) -> Result<(), C
     }
     Ok(())
 }
-
-/// Removes trailing retain operation with empty attributes, if present.
-pub fn trim(delta: &mut RichTextDelta) {
-    if let Some(last) = delta.ops.last() {
-        if last.is_retain() && last.is_plain() {
-            delta.ops.pop();
-        }
-    }
-}

+ 1 - 15
shared-lib/lib-ot/src/core/delta/builder.rs

@@ -1,4 +1,4 @@
-use crate::core::{Attributes, Delta, Operation};
+use crate::core::{trim, Attributes, Delta, Operation};
 
 pub struct DeltaBuilder<T: Attributes> {
     delta: Delta<T>,
@@ -49,17 +49,3 @@ where
 
     pub fn build(self) -> Delta<T> { self.delta }
 }
-
-pub fn trim<T: Attributes>(delta: &mut Delta<T>) {
-    let remove_last = match delta.ops.last() {
-        None => false,
-        Some(op) => match op {
-            Operation::Delete(_) => false,
-            Operation::Retain(retain) => retain.is_plain(),
-            Operation::Insert(_) => false,
-        },
-    };
-    if remove_last {
-        delta.ops.pop();
-    }
-}

+ 16 - 5
shared-lib/lib-ot/src/core/delta/delta.rs

@@ -150,17 +150,17 @@ where
             return Err(ErrorBuilder::new(OTErrorCode::IncompatibleLength).build());
         }
         let mut new_s = String::new();
-        let chars = &mut s.chars();
+        let utf16_iter = &mut s.utf16_iter();
         for op in &self.ops {
             match &op {
                 Operation::Retain(retain) => {
-                    for c in chars.take(retain.n as usize) {
-                        new_s.push(c);
+                    for c in utf16_iter.take(retain.n as usize) {
+                        new_s.push_str(&c);
                     }
                 },
                 Operation::Delete(delete) => {
                     for _ in 0..*delete {
-                        chars.next();
+                        utf16_iter.next();
                     }
                 },
                 Operation::Insert(insert) => {
@@ -264,7 +264,6 @@ where
                 },
             }
         }
-
         Ok(new_delta)
     }
 
@@ -428,6 +427,18 @@ where
     }
 }
 
+/// Removes trailing retain operation with empty attributes, if present.
+pub fn trim<T>(delta: &mut Delta<T>)
+where
+    T: Attributes,
+{
+    if let Some(last) = delta.ops.last() {
+        if last.is_retain() && last.is_plain() {
+            delta.ops.pop();
+        }
+    }
+}
+
 fn invert_from_other<T: Attributes>(
     base: &mut Delta<T>,
     other: &Delta<T>,