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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
---@class string.merger.diff
---@field start integer # 替换开始的字节
---@field finish integer # 替换结束的字节
---@field text string # 替换的文本
---@class string.merger.info: string.merger.diff
---@field cstart integer # 转换后的开始字节
---@field cfinish integer # 转换后的结束字节
---@alias string.merger.diffs string.merger.diff[]
---@alias string.merger.infos string.merger.info[]
-- 根据二分法找到最近的开始位置
---@param diffs table
---@param offset any
---@return string.merger.info
local function getNearDiff(diffs, offset, key)
local min = 1
local max = #diffs
while max > min do
local middle = min + (max - min) // 2
local diff = diffs[middle]
local ndiff = diffs[middle + 1]
if diff[key] > offset then
max = middle
goto CONTINUE
end
if not ndiff then
return diff
end
if ndiff[key] > offset then
return diff
end
if min == middle then
min = middle + 1
else
min = middle
end
::CONTINUE::
end
return diffs[min]
end
local m = {}
---把文本与差异进行合并
---@param text string
---@param diffs string.merger.diffs
---@return string
---@return string.merger.infos
function m.mergeDiff(text, diffs)
local info = {}
for i, diff in ipairs(diffs) do
info[i] = {
start = diff.start,
finish = diff.finish,
text = diff.text,
}
end
table.sort(info, function (a, b)
return a.start < b.start
end)
local cur = 1
local buf = {}
local delta = 0
for _, diff in ipairs(info) do
diff.cstart = diff.start + delta
diff.cfinish = diff.cstart + #diff.text - 1
buf[#buf+1] = text:sub(cur, diff.start - 1)
buf[#buf+1] = diff.text
cur = diff.finish + 1
delta = delta + #diff.text - (diff.finish - diff.start + 1)
end
buf[#buf+1] = text:sub(cur)
return table.concat(buf), info
end
---根据转换前的位置获取转换后的位置
---@param info string.merger.infos
---@param offset integer
---@return integer start
---@return integer finish
function m.getOffset(info, offset)
local diff = getNearDiff(info, offset, 'start')
if not diff then
return offset, offset
end
if offset <= diff.finish then
local start, finish
if offset == diff.start then
start = diff.cstart
end
if offset == diff.finish then
finish = diff.cfinish
end
if not start or not finish then
local soff = offset - diff.start
local pos = math.min(diff.cstart + soff, diff.cfinish)
start = start or pos
finish = finish or pos
end
if start > finish then
start = finish
end
return start, finish
end
local pos = offset - diff.finish + diff.cfinish
return pos, pos
end
---根据转换后的位置获取转换前的位置
---@param info string.merger.infos
---@param offset integer
---@return integer start
---@return integer finish
function m.getOffsetBack(info, offset)
local diff = getNearDiff(info, offset, 'cstart')
if not diff then
return offset, offset
end
if offset <= diff.cfinish then
local start, finish
if offset == diff.cstart then
start = diff.start
end
if offset == diff.cfinish then
finish = diff.finish
end
if not start or not finish then
local soff = offset - diff.cstart
local pos = math.min(diff.start + soff, diff.finish)
start = start or pos
finish = finish or pos
end
if start > finish then
start = finish
end
return start, finish
end
local pos = offset - diff.cfinish + diff.finish
return pos, pos
end
return m
|