fix merge attributes bug

This commit is contained in:
appflowy 2021-08-04 22:33:16 +08:00
parent b322f40ff7
commit c960d063fb
6 changed files with 151 additions and 66 deletions

View File

@ -16,15 +16,24 @@ pub enum Attributes {
impl Attributes { impl Attributes {
pub fn extend(&self, other: Option<Attributes>) -> Attributes { pub fn extend(&self, other: Option<Attributes>) -> Attributes {
log::debug!("Attribute extend: {:?} with {:?}", self, other);
let other = other.unwrap_or(Attributes::Empty); let other = other.unwrap_or(Attributes::Empty);
match (self, &other) { let result = match (self, &other) {
(Attributes::Custom(data), Attributes::Custom(o_data)) => { (Attributes::Custom(data), Attributes::Custom(o_data)) => {
let mut data = data.clone(); if !data.is_plain() {
data.extend(o_data.clone()); let mut data = data.clone();
Attributes::Custom(data) data.extend(o_data.clone());
Attributes::Custom(data)
} else {
Attributes::Custom(data.clone())
}
}, },
(Attributes::Custom(data), _) => Attributes::Custom(data.clone()),
// (Attributes::Empty, _) => Attributes::Empty,
_ => other, _ => other,
} };
log::debug!("result {:?}", result);
result
} }
// remove attribute if the value is PLAIN // remove attribute if the value is PLAIN
// { "k": PLAIN } -> {} // { "k": PLAIN } -> {}
@ -156,21 +165,29 @@ pub fn compose_attributes(left: &Option<Operation>, right: &Option<Operation>) -
log::trace!("compose_attributes: a: {:?}, b: {:?}", attr_l, attr_r); log::trace!("compose_attributes: a: {:?}, b: {:?}", attr_l, attr_r);
let mut attr = match (&attr_l, &attr_r) { let mut attr = match (&attr_l, &attr_r) {
(_, Some(Attributes::Custom(_))) => match &attr_l { (_, Some(Attributes::Custom(_))) => match attr_l {
None => attr_r.unwrap(), None => attr_r.unwrap(),
Some(_) => attr_l.unwrap().extend(attr_r.clone()), Some(_) => attr_l.unwrap().extend(attr_r.clone()),
// Some(attr_l) => merge_attributes(attr_l, attr_r),
}, },
(Some(Attributes::Custom(_)), _) => attr_l.unwrap().extend(attr_r), (Some(Attributes::Custom(_)), _) => attr_l.unwrap().extend(attr_r),
// (Some(Attributes::Custom(_)), _) => merge_attributes(attr_l.unwrap(), attr_r),
(Some(Attributes::Follow), Some(Attributes::Follow)) => Attributes::Follow, (Some(Attributes::Follow), Some(Attributes::Follow)) => Attributes::Follow,
_ => Attributes::Empty, _ => Attributes::Empty,
}; };
log::trace!("composed_attributes: a: {:?}", attr); log::trace!("composed_attributes: a: {:?}", attr);
// remove the attribute if the value is PLAIN match &mut attr {
attr.remove_plain(); Attributes::Custom(data) => {
data.remove_plain();
attr match data.is_plain() {
true => Attributes::Empty,
false => attr,
}
},
_ => attr,
}
} }
pub fn transform_attributes( pub fn transform_attributes(
@ -248,3 +265,16 @@ fn transform_attribute_data(left: AttributesData, right: AttributesData) -> Attr
}); });
result result
} }
pub fn merge_attributes(attributes: Attributes, other: Option<Attributes>) -> Attributes {
let other = other.unwrap_or(Attributes::Empty);
match (&attributes, &other) {
(Attributes::Custom(data), Attributes::Custom(o_data)) => {
let mut data = data.clone();
data.extend(o_data.clone());
Attributes::Custom(data)
},
(Attributes::Custom(data), _) => Attributes::Custom(data.clone()),
_ => other,
}
}

View File

@ -472,41 +472,45 @@ impl Delta {
return inverted; return inverted;
} }
let a = |inverted: &mut Delta, op: &Operation, index: usize, op_len: usize| { let inverted_from_other =
let ops = other.ops_in_interval(Interval::new(index, op_len)); |inverted: &mut Delta, operation: &Operation, index: usize, op_len: usize| {
ops.into_iter().for_each(|other_op| match op { let ops = other.ops_in_interval(Interval::new(index, op_len));
Operation::Delete(_) => { ops.into_iter().for_each(|other_op| {
inverted.add(other_op); match operation {
}, Operation::Delete(_) => {
Operation::Retain(_) => {}, inverted.add(other_op);
Operation::Insert(_) => { },
if !op.is_plain() { Operation::Retain(_) => {
let inverted_attrs = let inverted_attrs = invert_attributes(
invert_attributes(op.get_attributes(), other_op.get_attributes()); operation.get_attributes(),
inverted.retain(other_op.length(), inverted_attrs); other_op.get_attributes(),
);
inverted.retain(other_op.length(), inverted_attrs);
},
Operation::Insert(_) => {
// Impossible to here
},
} }
}, });
}); };
};
let mut index = 0; let mut index = 0;
for op in &self.ops { for op in &self.ops {
let op_len: usize = op.length() as usize; let len: usize = op.length() as usize;
match op { match op {
Operation::Delete(_) => { Operation::Delete(_) => {
a(&mut inverted, op, index, op_len); inverted_from_other(&mut inverted, op, index, len);
index += op_len; index += len;
}, },
Operation::Retain(_) => { Operation::Retain(_) => {
if op.is_plain() { match op.is_plain() {
inverted.retain(op_len as u64, op.get_attributes()); true => inverted.retain(len as u64, op.get_attributes()),
} else { false => inverted_from_other(&mut inverted, op, index, len as usize),
a(&mut inverted, op, index, op_len as usize);
} }
index += op_len; index += len;
}, },
Operation::Insert(insert) => { Operation::Insert(_) => {
inverted.delete(op_len as u64); inverted.delete(len as u64);
}, },
} }
} }
@ -565,16 +569,19 @@ impl Delta {
// } // }
// } // }
}, },
Operation::Insert(insert) => match &insert.attributes { Operation::Insert(insert) => {
Attributes::Follow => {}, let end = insert.num_chars() as usize;
Attributes::Custom(data) => { match &insert.attributes {
let end = insert.num_chars() as usize; Attributes::Follow => {},
if interval.contains_range(offset, offset + end) { Attributes::Custom(data) => {
attributes_data.extend(data.clone()); log::debug!("get attributes from op: {:?} at {:?}", op, interval);
} if interval.contains_range(offset, offset + end) {
offset += end; attributes_data.extend(data.clone());
}, }
Attributes::Empty => {}, },
Attributes::Empty => {},
}
offset += end
}, },
}); });

View File

@ -40,10 +40,12 @@ impl Operation {
match self { match self {
Operation::Delete(_) => {}, Operation::Delete(_) => {},
Operation::Retain(retain) => { Operation::Retain(retain) => {
retain.attributes.extend(Some(attributes)); let a = retain.attributes.extend(Some(attributes));
retain.attributes = a;
}, },
Operation::Insert(insert) => { Operation::Insert(insert) => {
insert.attributes.extend(Some(attributes)); let a = insert.attributes.extend(Some(attributes));
insert.attributes = a;
}, },
} }
} }

View File

@ -174,7 +174,7 @@ fn delta_add_bold_italic2() {
Italic(0, Interval::new(4, 6), true), Italic(0, Interval::new(4, 6), true),
AssertOpsJson( AssertOpsJson(
0, 0,
r#"[{"insert":"12","attributes":{"bold":"true","italic":"true"}},{"insert":"34","attributes":{"bold":"true"}},{"insert":"56","attributes":{"italic":"true"}}]"#, r#"[{"insert":"12","attributes":{"italic":"true","bold":"true"}},{"insert":"34","attributes":{"bold":"true"}},{"insert":"56","attributes":{"italic":"true","bold":"true"}}]"#,
), ),
]; ];
@ -221,7 +221,7 @@ fn delta_add_bold_italic_delete() {
Delete(0, Interval::new(0, 5)), Delete(0, Interval::new(0, 5)),
AssertOpsJson( AssertOpsJson(
0, 0,
r#"[{"insert":"67","attributes":{"bold":"true"}},{"insert":"89"}]"#, r#"[{"insert":"67"},{"insert":"89","attributes":{"bold":"true"}}]"#,
), ),
]; ];
@ -263,18 +263,18 @@ fn delta_compose_attr_delta_with_attr_delta_test2() {
Italic(0, Interval::new(4, 6), true), Italic(0, Interval::new(4, 6), true),
AssertOpsJson( AssertOpsJson(
0, 0,
r#"[{"insert":"12","attributes":{"bold":"true","italic":"true"}},{"insert":"34","attributes":{"bold":"true"}},{"insert":"56","attributes":{"italic":"true"}}]"#, r#"[{"insert":"12","attributes":{"bold":"true","italic":"true"}},{"insert":"34","attributes":{"bold":"true"}},{"insert":"56","attributes":{"italic":"true","bold":"true"}}]"#,
), ),
InsertBold(1, "7", Interval::new(0, 1)), InsertBold(1, "7", Interval::new(0, 1)),
AssertOpsJson(1, r#"[{"insert":"7","attributes":{"bold":"true"}}]"#), AssertOpsJson(1, r#"[{"insert":"7","attributes":{"bold":"true"}}]"#),
Transform(0, 1), Transform(0, 1),
AssertOpsJson( AssertOpsJson(
0, 0,
r#"[{"insert":"12","attributes":{"italic":"true","bold":"true"}},{"insert":"34","attributes":{"bold":"true"}},{"insert":"56","attributes":{"italic":"true"}},{"insert":"7","attributes":{"bold":"true"}}]"#, r#"[{"insert":"12","attributes":{"italic":"true","bold":"true"}},{"insert":"34","attributes":{"bold":"true"}},{"insert":"56","attributes":{"italic":"true","bold":"true"}},{"insert":"7","attributes":{"bold":"true"}}]"#,
), ),
AssertOpsJson( AssertOpsJson(
1, 1,
r#"[{"insert":"12","attributes":{"italic":"true","bold":"true"}},{"insert":"34","attributes":{"bold":"true"}},{"insert":"56","attributes":{"italic":"true"}},{"insert":"7","attributes":{"bold":"true"}}]"#, r#"[{"insert":"12","attributes":{"italic":"true","bold":"true"}},{"insert":"34","attributes":{"bold":"true"}},{"insert":"56","attributes":{"italic":"true","bold":"true"}},{"insert":"7","attributes":{"bold":"true"}}]"#,
), ),
]; ];

View File

@ -91,6 +91,7 @@ impl OpTester {
}, },
TestOp::AssertOpsJson(delta_i, expected) => { TestOp::AssertOpsJson(delta_i, expected) => {
log::debug!("AssertOpsJson: {:?}", self.deltas[*delta_i]);
let delta_i_json = serde_json::to_string(&self.deltas[*delta_i]).unwrap(); let delta_i_json = serde_json::to_string(&self.deltas[*delta_i]).unwrap();
let expected_delta: Delta = serde_json::from_str(expected).unwrap(); let expected_delta: Delta = serde_json::from_str(expected).unwrap();
@ -140,8 +141,13 @@ impl OpTester {
.attributes(attributes) .attributes(attributes)
.build(); .build();
let attributes = old_delta.attributes_in_interval(*interval); let attributes_in_interval = old_delta.attributes_in_interval(*interval);
retain.extend_attributes(attributes); retain.extend_attributes(attributes_in_interval);
log::debug!(
"Update delta with attributes: {:?} at: {:?}",
retain,
interval
);
let new_delta = new_delta_with_op(old_delta, retain, *interval); let new_delta = new_delta_with_op(old_delta, retain, *interval);
self.deltas[delta_index] = new_delta; self.deltas[delta_index] = new_delta;
@ -149,10 +155,7 @@ impl OpTester {
pub fn update_delta_with_delete(&mut self, delta_index: usize, interval: &Interval) { pub fn update_delta_with_delete(&mut self, delta_index: usize, interval: &Interval) {
let old_delta = &self.deltas[delta_index]; let old_delta = &self.deltas[delta_index];
let mut delete = OpBuilder::delete(interval.size() as u64).build(); let delete = OpBuilder::delete(interval.size() as u64).build();
let attributes = old_delta.attributes_in_interval(*interval);
delete.extend_attributes(attributes);
let new_delta = new_delta_with_op(old_delta, delete, *interval); let new_delta = new_delta_with_op(old_delta, delete, *interval);
self.deltas[delta_index] = new_delta; self.deltas[delta_index] = new_delta;
} }
@ -165,9 +168,14 @@ fn new_delta_with_op(delta: &Delta, op: Operation, interval: Interval) -> Delta
// prefix // prefix
if prefix.is_empty() == false && prefix != interval { if prefix.is_empty() == false && prefix != interval {
let intervals = split_interval_with_delta(delta, &prefix); let intervals = split_interval_with_delta(delta, &prefix);
intervals.into_iter().for_each(|interval| { intervals.into_iter().for_each(|p_interval| {
let attributes = delta.attributes_in_interval(interval); let attributes = delta.attributes_in_interval(p_interval);
new_delta.retain(interval.size() as u64, attributes); log::debug!(
"prefix attribute: {:?}, interval: {:?}",
attributes,
p_interval
);
new_delta.retain(p_interval.size() as u64, attributes);
}); });
} }
@ -176,9 +184,14 @@ fn new_delta_with_op(delta: &Delta, op: Operation, interval: Interval) -> Delta
// suffix // suffix
if suffix.is_empty() == false { if suffix.is_empty() == false {
let intervals = split_interval_with_delta(delta, &suffix); let intervals = split_interval_with_delta(delta, &suffix);
intervals.into_iter().for_each(|interval| { intervals.into_iter().for_each(|s_interval| {
let attributes = delta.attributes_in_interval(interval); let attributes = delta.attributes_in_interval(s_interval);
new_delta.retain(interval.size() as u64, attributes); log::debug!(
"suffix attribute: {:?}, interval: {:?}",
attributes,
s_interval
);
new_delta.retain(s_interval.size() as u64, attributes);
}); });
} }

View File

@ -21,10 +21,43 @@ fn delta_invert_delta_test() {
#[test] #[test]
fn delta_invert_delta_test2() { fn delta_invert_delta_test2() {
let ops = vec![ let ops = vec![
Insert(0, "1234", 0), Insert(0, "123", 0),
Insert(1, "4567", 0), Insert(1, "4567", 0),
Invert(0, 1), Invert(0, 1),
AssertOpsJson(0, r#"[{"insert":"1234"}]"#), AssertOpsJson(0, r#"[{"insert":"123"}]"#),
];
OpTester::new().run_script(ops);
}
#[test]
fn delta_invert_delta_with_attribute() {
let ops = vec![
Insert(0, "123", 0),
Bold(0, Interval::new(0, 3), true),
AssertOpsJson(0, r#"[{"insert":"123","attributes":{"bold":"true"}}]"#),
Insert(1, "4567", 0),
Invert(0, 1),
AssertOpsJson(0, r#"[{"insert":"123","attributes":{"bold":"true"}}]"#),
];
OpTester::new().run_script(ops);
}
#[test]
fn delta_invert_delta() {
let ops = vec![
Insert(0, "123", 0),
Bold(0, Interval::new(0, 3), true),
Insert(0, "456", 3),
AssertOpsJson(0, r#"[{"insert":"123456","attributes":{"bold":"true"}}]"#),
Italic(0, Interval::new(2, 4), true),
AssertOpsJson(
0,
r#"[{"insert":"12","attributes":{"bold":"true"}},{"insert":"34","attributes":{"bold":"true","italic":"true"}},{"insert":"56","attributes":{"bold":"true"}}]"#,
),
/* Insert(1, "4567", 0),
*
* Invert(0, 1),
* AssertOpsJson(0, r#"[{"insert":"123","attributes":{"bold":"true"}}]"#), */
]; ];
OpTester::new().run_script(ops); OpTester::new().run_script(ops);
} }