correct the document delta by removing unnecessary op

This commit is contained in:
appflowy 2022-01-06 12:39:32 +08:00
parent b239f28d10
commit 9ca2d60f3f
6 changed files with 30 additions and 44 deletions

View File

@ -114,6 +114,7 @@ impl EditorCommandQueue {
let read_guard = self.document.read().await;
let mut server_prime: Option<RichTextDelta> = None;
let client_prime: RichTextDelta;
// The document is empty if its text is equal to the initial text.
if read_guard.is_empty::<NewlineDoc>() {
// Do nothing
client_prime = new_delta;
@ -122,7 +123,6 @@ impl EditorCommandQueue {
client_prime = c_prime;
server_prime = Some(s_prime);
}
drop(read_guard);
Ok::<TransformDeltas, CollaborateError>(TransformDeltas {
client_prime,

View File

@ -9,16 +9,12 @@ use flowy_collaboration::{
doc::DocumentInfo,
revision::{RepeatedRevision, Revision, RevisionRange, RevisionState},
},
util::{md5, pair_rev_id_from_revisions, RevIdCounter},
util::{make_delta_from_revisions, md5, pair_rev_id_from_revisions, RevIdCounter},
};
use flowy_error::FlowyResult;
use futures_util::{future, stream, stream::StreamExt};
use lib_infra::future::FutureResult;
use lib_ot::{
core::{trim, Operation, OperationTransformable},
errors::OTError,
rich_text::RichTextDelta,
};
use lib_ot::{core::Operation, errors::OTError, rich_text::RichTextDelta};
use std::{collections::VecDeque, sync::Arc};
use tokio::sync::RwLock;
@ -239,18 +235,8 @@ impl RevisionLoader {
fn mk_doc_from_revisions(doc_id: &str, revisions: Vec<Revision>) -> FlowyResult<DocumentInfo> {
let (base_rev_id, rev_id) = revisions.last().unwrap().pair_rev_id();
let mut delta = RichTextDelta::new();
for (_, revision) in revisions.into_iter().enumerate() {
match RichTextDelta::from_bytes(revision.delta_data) {
Ok(local_delta) => {
delta = delta.compose(&local_delta)?;
},
Err(e) => {
tracing::error!("Deserialize delta from revision failed: {}", e);
},
}
}
correct_delta_if_need(&mut delta);
let mut delta = make_delta_from_revisions(revisions)?;
correct_delta(&mut delta);
Result::<DocumentInfo, FlowyError>::Ok(DocumentInfo {
doc_id: doc_id.to_owned(),
@ -260,16 +246,20 @@ fn mk_doc_from_revisions(doc_id: &str, revisions: Vec<Revision>) -> FlowyResult<
})
}
fn correct_delta_if_need(delta: &mut RichTextDelta) {
trim(delta);
if delta.ops.last().is_none() {
return;
// quill-editor requires the delta should end with '\n' and only contains the
// insert operation. The function, correct_delta maybe be removed in the future.
fn correct_delta(delta: &mut RichTextDelta) {
if let Some(op) = delta.ops.last() {
let op_data = op.get_data();
if !op_data.ends_with('\n') {
log::warn!("The document must end with newline. Correcting it by inserting newline op");
delta.ops.push(Operation::Insert("\n".into()));
}
}
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");
delta.ops.push(Operation::Insert("\n".into()));
if let Some(op) = delta.ops.iter().find(|op| !op.is_insert()) {
log::warn!("The document can only contains insert operations, but found {:?}", op);
delta.ops.retain(|op| op.is_insert());
}
}

View File

@ -130,17 +130,12 @@ impl DocumentWSSinkDataProvider for DocumentWSSinkDataProviderAdapter {
}
async fn transform_pushed_revisions(
revisions: &[Revision],
revisions: Vec<Revision>,
edit_cmd: &UnboundedSender<EditorCommand>,
) -> FlowyResult<TransformDeltas> {
let (ret, rx) = oneshot::channel::<CollaborateResult<TransformDeltas>>();
// Transform the revision
let _ = edit_cmd.send(EditorCommand::TransformRevision {
revisions: revisions.to_vec(),
ret,
});
let transformed_delta = rx.await.map_err(internal_error)??;
Ok(transformed_delta)
let _ = edit_cmd.send(EditorCommand::TransformRevision { revisions, ret });
Ok(rx.await.map_err(internal_error)??)
}
#[tracing::instrument(level = "debug", skip(edit_cmd_tx, rev_manager, bytes))]
@ -170,7 +165,8 @@ pub(crate) async fn handle_remote_revision(
let TransformDeltas {
client_prime,
server_prime,
} = transform_pushed_revisions(&revisions, &edit_cmd_tx).await?;
} = transform_pushed_revisions(revisions.clone(), &edit_cmd_tx).await?;
match server_prime {
None => {
// The server_prime is None means the client local revisions conflict with the

View File

@ -1,7 +1,6 @@
use std::sync::Arc;
use parking_lot::RwLock;
use serde::{Deserialize, Serialize};
use std::sync::Arc;
use tokio::sync::mpsc;
use backend_service::configuration::ClientServerConfiguration;
@ -293,6 +292,7 @@ struct Session {
user_id: String,
token: String,
email: String,
#[serde(default)]
name: String,
}

View File

@ -45,15 +45,15 @@ impl RevIdCounter {
}
pub fn make_delta_from_revisions(revisions: Vec<Revision>) -> CollaborateResult<RichTextDelta> {
let mut new_delta = RichTextDelta::new();
let mut delta = RichTextDelta::new();
for revision in revisions {
let delta = RichTextDelta::from_bytes(revision.delta_data).map_err(|e| {
let revision_delta = RichTextDelta::from_bytes(revision.delta_data).map_err(|e| {
let err_msg = format!("Deserialize remote revision failed: {:?}", e);
CollaborateError::internal().context(err_msg)
})?;
new_delta = new_delta.compose(&delta)?;
delta = delta.compose(&revision_delta)?;
}
Ok(new_delta)
Ok(delta)
}
pub fn make_delta_from_revision_pb(revisions: Vec<RevisionPB>) -> CollaborateResult<RichTextDelta> {

View File

@ -241,7 +241,7 @@ where
.next_op_with_len(length)
.unwrap_or_else(|| OpBuilder::retain(length).build());
debug_assert_eq!(op.len(), other_op.len());
// debug_assert_eq!(op.len(), other_op.len(), "Composing delta failed,");
match (&op, &other_op) {
(Operation::Retain(retain), Operation::Retain(other_retain)) => {