import Foundation public struct GitDiffHunk: Identifiable, Sendable, Equatable { public let id: Int public let fileHeader: String public let lines: [String] public var patch: String { fileHeader + lines.joined(separator: "\n") + "\n" } public var title: String { lines.first ?? "Changes" } } public enum GitDiffParser { /// Retains each file's complete header so a selected hunk remains a valid Git patch. public static func hunks(_ diff: String) -> [GitDiffHunk] { var result: [GitDiffHunk] = [] var header: [String] = [] var lines: [String] = [] func flush() { guard !lines.isEmpty else { return } result.append( GitDiffHunk(id: result.count, fileHeader: header.joined(separator: "\n") + "\n", lines: lines)) lines.removeAll() } var source = diff.components(separatedBy: "\n") if source.last == "" { source.removeLast() } for line in source { if line.hasPrefix("diff --git ") { flush() header = [line] } else if line.hasPrefix("@@ ") { flush() lines = [line] } else if !lines.isEmpty { lines.append(line) } else { header.append(line) } } flush() return result } } public struct GitDiffRow: Identifiable, Sendable, Equatable { public let id: Int public let original: String public let modified: String } extension GitDiffParser { public static func pairedRows(_ hunk: GitDiffHunk) -> [GitDiffRow] { var result: [GitDiffRow] = [] var removed: [String] = [] var added: [String] = [] func flush() { for index in 0..