-
Notifications
You must be signed in to change notification settings - Fork 8
/
gitdiff.lua
112 lines (94 loc) · 2.41 KB
/
gitdiff.lua
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
106
107
108
109
110
111
112
-- mod-version:1
local gitdiff = {}
-- liquidev is a genius
local function extract_hunks(input)
local hunks = {}
local current_hunk = {}
local function end_hunk(new_line)
if #current_hunk > 0 then
table.insert(hunks, current_hunk)
current_hunk = { new_line }
end
end
for line in input:gmatch("(.-)\n") do
if line:match("^@") then
end_hunk(line)
else
table.insert(current_hunk, line)
end
end
-- add the last hunk to the table
end_hunk("")
return hunks
end
-- determines if line is a hunk header and returns
-- the starting line of changed version (second set of numbers part before
-- optional comma) or nil
---@param line string
---@return integer | nil
local function get_hunk_start(line)
if "string" ~= type(line) or not line:match("^@@[^@]+@@") then
return nil
end
-- doing "@@%s+-%d+(,%d+)?%s++(%d-)(,%d+)?%s+@@" did not work
-- so we loop through a couple of patterns
local patterns = {
"@@%s+-%d+,%d+%s++(%d-),%d+%s+@@",
"@@%s+-%d+%s++(%d-),%d+%s+@@",
"@@%s+-%d+,%d+%s++(%d-)%s+@@",
"@@%s+-%d+%s++(%d-)%s+@@"
}
local start
for _, p in ipairs(patterns) do
start = line:match(p)
if start then return tonumber(start) end
end
return nil
end
-- this will only work on single-file diffs
function gitdiff.changed_lines(diff)
if not diff then return {} end
local changed_lines = {}
local hunks = extract_hunks(diff)
-- iterate over hunks
for _, hunk in ipairs(hunks) do
local current_line
local hunk_start = get_hunk_start(hunk[1])
if not hunk_start then -- mod
goto continue
end
current_line = hunk_start - 1
-- remove hunk header
hunk[1] = ""
for _, line in ipairs(hunk) do
if line:match("^%s-%[%-.-%-]$") then
table.insert(changed_lines, {
line_number = current_line,
change_type = "deletion"
})
-- do not add to the current line
goto skip_line
end
if line:match("^%s-{%+.-+}$") then
table.insert(changed_lines, {
line_number = current_line,
change_type = "addition"
})
elseif line:match("{%+.-+}") or line:match("%[%-.-%-]") then
table.insert(changed_lines, {
line_number = current_line,
change_type = "modification"
})
end
current_line = current_line + 1
::skip_line::
end
::continue::
end
local indexed_changed_lines = {}
for _, line in ipairs(changed_lines) do
indexed_changed_lines[line.line_number] = line.change_type
end
return indexed_changed_lines
end
return gitdiff