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