compose method

Delta compose(
  1. Delta other
)

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();
}