groupedOperations method
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;
}
}