groupedOperations method

Iterable<List<Operation>> groupedOperations({
  1. int context = 3,
})

Returns a sequence of operations describing how to turn source into target keeping a context of lines before and after each change.

Implementation

Iterable<List<Operation>> groupedOperations({int context = 3}) sync* {
  if (context < 0) throw ArgumentError.value(context, 'context');
  final codes = [...operations];
  if (codes.isEmpty) codes.add(Operation.empty);
  if (codes.first.type == OperationType.equal) {
    final Operation(
      :type,
      :sourceStart,
      :sourceEnd,
      :targetStart,
      :targetEnd
    ) = codes.first;
    codes.first = Operation(
      type,
      sourceStart: max(sourceStart, sourceEnd - context),
      sourceEnd: sourceEnd,
      targetStart: max(targetStart, targetEnd - context),
      targetEnd: targetEnd,
    );
  }
  if (codes.last.type == OperationType.equal) {
    final Operation(
      :type,
      :sourceStart,
      :sourceEnd,
      :targetStart,
      :targetEnd
    ) = codes.last;
    codes.last = Operation(
      type,
      sourceStart: sourceStart,
      sourceEnd: min(sourceEnd, sourceStart + context),
      targetStart: targetStart,
      targetEnd: min(targetEnd, targetStart + context),
    );
  }
  final group = <Operation>[];
  for (final code in codes) {
    var Operation(:type, :sourceStart, :sourceEnd, :targetStart, :targetEnd) =
        code;
    if (type == OperationType.equal &&
        sourceEnd - sourceStart > 2 * context) {
      group.add(Operation(
        type,
        sourceStart: sourceStart,
        sourceEnd: min(sourceEnd, sourceStart + context),
        targetStart: targetStart,
        targetEnd: min(targetEnd, targetStart + context),
      ));
      yield group;
      group.clear();
      sourceStart = max(sourceStart, sourceEnd - context);
      targetStart = max(targetStart, targetEnd - context);
    }
    group.add(Operation(
      type,
      sourceStart: sourceStart,
      sourceEnd: sourceEnd,
      targetStart: targetStart,
      targetEnd: targetEnd,
    ));
  }
  if (group.isNotEmpty &&
      !(group.length == 1 && group.first.type == OperationType.equal)) {
    yield group;
  }
}