fix: use retain instead of insert/delete for same attr (#937)
* fix: use retain instead of insert/delete for same attr * test: add delta diff test
This commit is contained in:
parent
5cb871d3f5
commit
450912305a
3 changed files with 73 additions and 2 deletions
|
|
@ -52,6 +52,23 @@ Attributes invertAttributes(Attributes? from, Attributes? to) {
|
||||||
return attributes;
|
return attributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Attributes? diffAttributes(
|
||||||
|
Map<String, dynamic>? from,
|
||||||
|
Map<String, dynamic>? to,
|
||||||
|
) {
|
||||||
|
from ??= const {};
|
||||||
|
to ??= const {};
|
||||||
|
final attributes = Attributes.from({});
|
||||||
|
|
||||||
|
for (final key in (from.keys.toList()..addAll(to.keys))) {
|
||||||
|
if (from[key] != to[key]) {
|
||||||
|
attributes[key] = to.containsKey(key) ? to[key] : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return attributes;
|
||||||
|
}
|
||||||
|
|
||||||
int hashAttributes(Attributes base) => Object.hashAllUnordered(
|
int hashAttributes(Attributes base) => Object.hashAllUnordered(
|
||||||
base.entries.map((e) => Object.hash(e.key, e.value)),
|
base.entries.map((e) => Object.hash(e.key, e.value)),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,10 @@ const int _maxInt = 9007199254740991;
|
||||||
|
|
||||||
sealed class TextOperation {
|
sealed class TextOperation {
|
||||||
Attributes? get attributes;
|
Attributes? get attributes;
|
||||||
|
|
||||||
|
// available for TextInsert, for TextDelete and TextRetain, it's null
|
||||||
|
Object? get data => null;
|
||||||
|
|
||||||
int get length;
|
int get length;
|
||||||
|
|
||||||
bool get isEmpty => length == 0;
|
bool get isEmpty => length == 0;
|
||||||
|
|
@ -81,6 +85,9 @@ class TextInsert extends TextOperation {
|
||||||
@override
|
@override
|
||||||
int get length => text.length;
|
int get length => text.length;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Object? get data => text;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Attributes? get attributes => _attributes != null ? {..._attributes} : null;
|
Attributes? get attributes => _attributes != null ? {..._attributes} : null;
|
||||||
|
|
||||||
|
|
@ -402,10 +409,10 @@ class Delta extends Iterable<TextOperation> {
|
||||||
);
|
);
|
||||||
final thisOp = thisIter.next(opLength);
|
final thisOp = thisIter.next(opLength);
|
||||||
final otherOp = otherIter.next(opLength);
|
final otherOp = otherIter.next(opLength);
|
||||||
if (isAttributesEqual(thisOp.attributes, otherOp.attributes)) {
|
if (thisOp.data == otherOp.data) {
|
||||||
retDelta.retain(
|
retDelta.retain(
|
||||||
opLength,
|
opLength,
|
||||||
attributes: invertAttributes(
|
attributes: diffAttributes(
|
||||||
thisOp.attributes,
|
thisOp.attributes,
|
||||||
otherOp.attributes,
|
otherOp.attributes,
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -519,6 +519,53 @@ void main() {
|
||||||
final diff = delta.diff(restored);
|
final diff = delta.diff(restored);
|
||||||
expect(delta.compose(diff), restored);
|
expect(delta.compose(diff), restored);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('insert', () {
|
||||||
|
final a = Delta()..insert('Hello');
|
||||||
|
final b = Delta()..insert('Hello!');
|
||||||
|
final expected = Delta()
|
||||||
|
..retain(5)
|
||||||
|
..insert('!');
|
||||||
|
expect(a.diff(b), expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('delete', () {
|
||||||
|
final a = Delta()..insert('Hello!');
|
||||||
|
final b = Delta()..insert('Hello');
|
||||||
|
final expected = Delta()
|
||||||
|
..retain(5)
|
||||||
|
..delete(1);
|
||||||
|
expect(a.diff(b), expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('retain', () {
|
||||||
|
final a = Delta()..insert('A');
|
||||||
|
final b = Delta()..insert('A');
|
||||||
|
final expected = Delta();
|
||||||
|
expect(a.diff(b), expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('retain with attributes - 1', () {
|
||||||
|
final a = Delta()..insert('Hello');
|
||||||
|
final b = Delta()..insert('Hello', attributes: {'bold': true});
|
||||||
|
final expected = Delta()
|
||||||
|
..retain(
|
||||||
|
5,
|
||||||
|
attributes: {'bold': true},
|
||||||
|
);
|
||||||
|
expect(a.diff(b), expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('retain with attributes - 2', () {
|
||||||
|
final a = Delta()..insert('Hello', attributes: {'bold': true});
|
||||||
|
final b = Delta()..insert('Hello', attributes: {'italic': true});
|
||||||
|
final expected = Delta()
|
||||||
|
..retain(
|
||||||
|
5,
|
||||||
|
attributes: {'bold': null, 'italic': true},
|
||||||
|
);
|
||||||
|
expect(a.diff(b), expected);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue