diff method
Returns a Delta containing differences between 2 Deltas.
If cleanupSemantic
is true
(default), applies the following:
The diff of "mouse" and "sofas" is
delete(1), insert("s"), retain(1),
delete("u"), insert("fa"), retain(1), delete(1).
While this is the optimum diff, it is difficult for humans to understand.
Semantic cleanup rewrites the diff,
expanding it into a more intelligible format.
The above example would become: (-1, "mouse"), (1, "sofas")
.
(source: https://github.com/google/diff-match-patch/wiki/API)
Useful when one wishes to display difference between 2 documents
Implementation
Delta diff(Delta other, {bool cleanupSemantic = true}) {
if (operations.equals(other.operations)) {
return Delta();
}
final stringThis = map((op) {
if (op.isInsert) {
return op.data is String ? op.data : _kNullCharacter;
}
final prep = this == other ? 'on' : 'with';
throw ArgumentError('diff() call $prep non-document');
}).join();
final stringOther = other.map((op) {
if (op.isInsert) {
return op.data is String ? op.data : _kNullCharacter;
}
final prep = this == other ? 'on' : 'with';
throw ArgumentError('diff() call $prep non-document');
}).join();
final retDelta = Delta();
final diffResult = dmp.diff(stringThis, stringOther);
if (cleanupSemantic) {
dmp.DiffMatchPatch().diffCleanupSemantic(diffResult);
}
final thisIter = DeltaIterator(this);
final otherIter = DeltaIterator(other);
bool isEqual(Object? a, Object? b) =>
const DeepCollectionEquality.unordered().equals(a, b);
for (final component in diffResult) {
var length = component.text.length;
while (length > 0) {
var opLength = 0;
switch (component.operation) {
case dmp.DIFF_INSERT:
opLength = math.min(otherIter.peekLength(), length);
retDelta.push(otherIter.next(opLength));
break;
case dmp.DIFF_DELETE:
opLength = math.min(length, thisIter.peekLength());
thisIter.next(opLength);
retDelta.delete(opLength);
break;
case dmp.DIFF_EQUAL:
opLength = math.min(
math.min(thisIter.peekLength(), otherIter.peekLength()),
length,
);
final thisOp = thisIter.next(opLength);
final otherOp = otherIter.next(opLength);
if (isEqual(thisOp.data, otherOp.data)) {
retDelta.retain(
opLength,
diffAttributes(thisOp.attributes, otherOp.attributes),
);
} else {
retDelta
..push(otherOp)
..delete(opLength);
}
break;
}
length -= opLength;
}
}
return retDelta..trim();
}