mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
fix merge attributes bug
This commit is contained in:
parent
b322f40ff7
commit
c960d063fb
@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -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;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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"}}]"#,
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -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);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user