diff method

Delta diff(
  1. Delta other, {
  2. bool cleanupSemantic = true,
})

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