Repository navigation
Expand file tree
/
Copy pathsession_patch.lua
More file actions
86 lines (82 loc) · 2.97 KB
/
Copy pathsession_patch.lua
File metadata and controls
86 lines (82 loc) · 2.97 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
local M = {}
---@class OpencodeSessionPatchLine
---@field old? integer
---@field new? integer
---@param patch string
---@return OpencodeSessionPatchLine[]
function M.line_map(patch)
local map = {}
local old, new = 0, 0
local old_left, new_left = 0, 0
for row, line in ipairs(vim.split(patch:gsub('\r\n', '\n'), '\n', { plain = true, trimempty = true })) do
local old_start, old_size, new_start, new_size = line:match('^@@ %-(%d+),?(%d*) %+(%d+),?(%d*) @@')
map[row] = {}
if old_start then
old, new = tonumber(old_start) - 1, tonumber(new_start) - 1
old_left = old_size == '' and 1 or tonumber(old_size)
new_left = new_size == '' and 1 or tonumber(new_size)
elseif line:sub(1, 1) == ' ' and old_left > 0 and new_left > 0 then
old, new = old + 1, new + 1
old_left, new_left = old_left - 1, new_left - 1
map[row] = { old = old, new = new }
elseif line:sub(1, 1) == '-' and old_left > 0 then
old, old_left = old + 1, old_left - 1
map[row] = { old = old }
elseif line:sub(1, 1) == '+' and new_left > 0 then
new, new_left = new + 1, new_left - 1
map[row] = { new = new }
end
end
return map
end
---Reconstruct both revisions from a full-context unified patch.
---@param patch string
---@return string[]?, string[]?
function M.sides(patch)
local before, after = {}, {}
local old_pos, new_pos = 1, 1
---@type number, number
local old_count, new_count = 0, 0
local saw_hunk = false
for _, line in ipairs(vim.split(patch:gsub('\r\n', '\n'), '\n', { plain = true })) do
local old_start, old_size, new_start, new_size = line:match('^@@ %-(%d+),?(%d*) %+(%d+),?(%d*) @@')
if old_start then
if saw_hunk and (old_count ~= 0 or new_count ~= 0) then
return nil, nil
end
local old_length = old_size == '' and 1 or assert(tonumber(old_size))
local new_length = new_size == '' and 1 or assert(tonumber(new_size))
if
tonumber(old_start) ~= old_pos - (old_length == 0 and 1 or 0)
or tonumber(new_start) ~= new_pos - (new_length == 0 and 1 or 0)
then
return nil, nil
end
old_count, new_count = old_length, new_length
saw_hunk = true
elseif saw_hunk and (old_count > 0 or new_count > 0) then
local marker, text = line:sub(1, 1), line:sub(2)
if marker == ' ' then
before[#before + 1], after[#after + 1] = text, text
old_count, new_count = old_count - 1, new_count - 1
old_pos, new_pos = old_pos + 1, new_pos + 1
elseif marker == '-' then
before[#before + 1] = text
old_count, old_pos = old_count - 1, old_pos + 1
elseif marker == '+' then
after[#after + 1] = text
new_count, new_pos = new_count - 1, new_pos + 1
else
return nil, nil
end
if old_count < 0 or new_count < 0 then
return nil, nil
end
end
end
if not saw_hunk or old_count ~= 0 or new_count ~= 0 then
return nil, nil
end
return before, after
end
return M