parsePatch method

List<FileDiff> parsePatch(
  1. String patchText
)

Parse a unified diff / patch string into a list of FileDiff.

Implementation

List<FileDiff> parsePatch(String patchText) {
  final diffs = <FileDiff>[];
  final lines = patchText.split('\n');
  var i = 0;

  while (i < lines.length) {
    // Find next file header.
    if (i < lines.length && lines[i].startsWith('--- ')) {
      final oldPath = _stripPrefix(lines[i], '--- ');
      i++;
      if (i >= lines.length || !lines[i].startsWith('+++ ')) {
        continue;
      }
      final newPath = _stripPrefix(lines[i], '+++ ');
      i++;

      final hunks = <DiffHunk>[];

      while (i < lines.length && lines[i].startsWith('@@ ')) {
        final header = _parseHunkHeader(lines[i]);
        if (header == null) {
          i++;
          continue;
        }
        i++;

        final hunkLines = <DiffLine>[];
        var oldLine = header.oldStart;
        var newLine = header.newStart;

        while (i < lines.length &&
            !lines[i].startsWith('@@ ') &&
            !lines[i].startsWith('--- ')) {
          final raw = lines[i];
          if (raw.startsWith('+')) {
            hunkLines.add(
              DiffLine(
                type: DiffLineType.add,
                content: raw.substring(1),
                newLineNumber: newLine,
              ),
            );
            newLine++;
          } else if (raw.startsWith('-')) {
            hunkLines.add(
              DiffLine(
                type: DiffLineType.remove,
                content: raw.substring(1),
                oldLineNumber: oldLine,
              ),
            );
            oldLine++;
          } else if (raw.startsWith(' ') || raw.isEmpty) {
            final content = raw.isEmpty ? '' : raw.substring(1);
            hunkLines.add(
              DiffLine(
                type: DiffLineType.context,
                content: content,
                oldLineNumber: oldLine,
                newLineNumber: newLine,
              ),
            );
            oldLine++;
            newLine++;
          } else {
            // Unknown line, skip.
          }
          i++;
        }

        hunks.add(
          DiffHunk(
            oldStart: header.oldStart,
            oldCount: header.oldCount,
            newStart: header.newStart,
            newCount: header.newCount,
            lines: hunkLines,
          ),
        );
      }

      final stats = _computeStats(hunks);
      diffs.add(
        FileDiff(path: newPath, oldPath: oldPath, hunks: hunks, stats: stats),
      );
    } else {
      i++;
    }
  }
  return diffs;
}