createPatch function

PatchSet createPatch(
  1. String oldText,
  2. String newText, {
  3. int contextLines = 3,
})

Create a PatchSet from oldText to newText.

contextLines controls how many context lines surround each hunk.

Implementation

PatchSet createPatch(String oldText, String newText, {int contextLines = 3}) {
  final diffs = computeLineDiff(oldText, newText);
  if (diffs.every((d) => d.type == DiffType.context)) {
    return const PatchSet(hunks: []);
  }

  // Find ranges of changes and expand with context
  final changeIndices = <int>[];
  for (var i = 0; i < diffs.length; i++) {
    if (diffs[i].type != DiffType.context) {
      changeIndices.add(i);
    }
  }

  if (changeIndices.isEmpty) return const PatchSet(hunks: []);

  // Group changes into hunks
  final hunkGroups = <List<int>>[
    [changeIndices.first],
  ];
  for (var i = 1; i < changeIndices.length; i++) {
    if (changeIndices[i] - changeIndices[i - 1] <= contextLines * 2 + 1) {
      hunkGroups.last.add(changeIndices[i]);
    } else {
      hunkGroups.add([changeIndices[i]]);
    }
  }

  final hunks = <Hunk>[];
  for (final group in hunkGroups) {
    final start = math.max(0, group.first - contextLines);
    final end = math.min(diffs.length - 1, group.last + contextLines);
    final lines = diffs.sublist(start, end + 1);

    var oldStart = 1, newStart = 1;
    // Count lines up to start
    for (var i = 0; i < start; i++) {
      if (diffs[i].type != DiffType.add) oldStart++;
      if (diffs[i].type != DiffType.remove) newStart++;
    }

    var oldCount = 0, newCount = 0;
    for (final l in lines) {
      if (l.type != DiffType.add) oldCount++;
      if (l.type != DiffType.remove) newCount++;
    }

    hunks.add(
      Hunk(
        oldStart: oldStart,
        oldCount: oldCount,
        newStart: newStart,
        newCount: newCount,
        lines: lines,
      ),
    );
  }

  return PatchSet(hunks: hunks);
}