compose method
Returns a Delta that is equivalent to applying the operations of own Delta, followed by another Delta.
Implementation
Delta compose(Delta other) {
final thisIter = _OpIterator(_operations);
final otherIter = _OpIterator(other._operations);
final operations = <TextOperation>[];
final firstOther = otherIter.peek();
if (firstOther != null &&
firstOther is TextRetain &&
firstOther.attributes == null) {
int firstLeft = firstOther.length;
while (
thisIter.peek() is TextInsert && thisIter.peekLength() <= firstLeft) {
firstLeft -= thisIter.peekLength();
final next = thisIter.next();
operations.add(next);
}
if (firstOther.length - firstLeft > 0) {
otherIter.next(firstOther.length - firstLeft);
}
}
final delta = Delta(operations: operations);
while (thisIter.hasNext || otherIter.hasNext) {
if (otherIter.peek() is TextInsert) {
final next = otherIter.next();
delta.add(next);
} else if (thisIter.peek() is TextDelete) {
final next = thisIter.next();
delta.add(next);
} else {
// otherIs
final length = min(thisIter.peekLength(), otherIter.peekLength());
final thisOp = thisIter.next(length);
final otherOp = otherIter.next(length);
final attributes = composeAttributes(
thisOp.attributes,
otherOp.attributes,
keepNull: thisOp is TextRetain,
);
if (otherOp is TextRetain && otherOp.length > 0) {
TextOperation? newOp;
if (thisOp is TextRetain) {
newOp = TextRetain(length, attributes: attributes);
} else if (thisOp is TextInsert) {
newOp = TextInsert(thisOp.text, attributes: attributes);
}
if (newOp != null) {
delta.add(newOp);
}
// Optimization if rest of other is just retain
if (!otherIter.hasNext &&
delta._operations.isNotEmpty &&
delta._operations.last == newOp) {
final rest = Delta(operations: thisIter.rest());
return (delta + rest)..chop();
}
} else if (otherOp is TextDelete && (thisOp is TextRetain)) {
delta.add(otherOp);
}
}
}
return delta..chop();
}