-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Expand file tree
/
Copy pathGitHunk.swift
More file actions
105 lines (90 loc) · 3.58 KB
/
GitHunk.swift
File metadata and controls
105 lines (90 loc) · 3.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import Foundation
public struct GitHunk {
public let startDeletedLine: Int // 1-based
public let deletedLines: Int
public let startAddedLine: Int // 1-based
public let addedLines: Int
public let additions: [(start: Int, length: Int)]
public let diffText: String
public init(
startDeletedLine: Int,
deletedLines: Int,
startAddedLine: Int,
addedLines: Int,
additions: [(start: Int, length: Int)],
diffText: String
) {
self.startDeletedLine = startDeletedLine
self.deletedLines = deletedLines
self.startAddedLine = startAddedLine
self.addedLines = addedLines
self.additions = additions
self.diffText = diffText
}
}
public extension GitHunk {
static func parseDiff(_ diff: String) -> [GitHunk] {
var hunkTexts = diff.components(separatedBy: "\n@@")
if !hunkTexts.isEmpty, hunkTexts.last?.hasSuffix("\n") == true {
hunkTexts[hunkTexts.count - 1] = String(hunkTexts.last!.dropLast())
}
let hunks: [GitHunk] = hunkTexts.compactMap { chunk -> GitHunk? in
let rangePattern = #"-(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))?"#
let regex = try! NSRegularExpression(pattern: rangePattern)
let nsString = chunk as NSString
guard let match = regex.firstMatch(
in: chunk,
options: [],
range: NSRange(location: 0, length: nsString.length)
)
else { return nil }
var startDeletedLine = Int(nsString.substring(with: match.range(at: 1))) ?? 0
let deletedLines = match.range(at: 2).location != NSNotFound
? Int(nsString.substring(with: match.range(at: 2))) ?? 1
: 1
var startAddedLine = Int(nsString.substring(with: match.range(at: 3))) ?? 0
let addedLines = match.range(at: 4).location != NSNotFound
? Int(nsString.substring(with: match.range(at: 4))) ?? 1
: 1
var additions: [(start: Int, length: Int)] = []
let lines = Array(chunk.components(separatedBy: "\n").dropFirst())
var d = 0
var addStart: Int?
for line in lines {
let ch = line.first ?? Character(" ")
if ch == "+" {
if addStart == nil {
addStart = startAddedLine + d
}
d += 1
} else {
if let start = addStart {
additions.append((start: start, length: startAddedLine + d - start))
addStart = nil
}
if ch == " " {
d += 1
}
}
}
if let start = addStart {
additions.append((start: start, length: startAddedLine + d - start))
}
if startDeletedLine == 0 {
startDeletedLine = 1
}
if startAddedLine == 0 {
startAddedLine = 1
}
return GitHunk(
startDeletedLine: startDeletedLine,
deletedLines: deletedLines,
startAddedLine: startAddedLine,
addedLines: addedLines,
additions: additions,
diffText: lines.joined(separator: "\n")
)
}
return hunks
}
}