wao 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/aoconnect.js +2 -2
- package/{test/lua/aos.wasm → cjs/lua/aos2_0_1.wasm} +0 -0
- package/cjs/utils.js +1 -16
- package/esm/aoconnect.js +2 -2
- package/esm/utils.js +0 -18
- package/package.json +1 -1
- package/test/aoconnect.js +2 -2
- package/test/package.json +1 -1
- package/test/utils.js +0 -18
- package/esm/lua/aos-sqlite.wasm +0 -0
- package/esm/lua/aos.wasm +0 -0
- package/esm/lua/aos2.lua +0 -33
- package/esm/lua/atomic-asset.lua +0 -238
- package/esm/lua/atomic-note-library.lua +0 -2274
- package/esm/lua/atomic-note.lua +0 -11
- package/esm/lua/collection-registry.lua +0 -202
- package/esm/lua/collection.lua +0 -173
- package/esm/lua/notebook.lua +0 -173
- package/esm/lua/profile.lua +0 -858
- package/esm/lua/profile000.lua +0 -666
- package/esm/lua/proxy.lua +0 -24
- package/esm/lua/registry.lua +0 -858
- package/esm/lua/registry000.lua +0 -636
- package/test/lua/aos-sqlite.wasm +0 -0
- package/test/lua/aos2.lua +0 -33
- package/test/lua/atomic-asset.lua +0 -238
- package/test/lua/atomic-note-library.lua +0 -2274
- package/test/lua/atomic-note.lua +0 -11
- package/test/lua/collection-registry.lua +0 -202
- package/test/lua/collection.lua +0 -173
- package/test/lua/notebook.lua +0 -173
- package/test/lua/profile.lua +0 -858
- package/test/lua/profile000.lua +0 -666
- package/test/lua/proxy.lua +0 -24
- package/test/lua/registry.lua +0 -858
- package/test/lua/registry000.lua +0 -636
|
@@ -1,2274 +0,0 @@
|
|
|
1
|
-
semver = {
|
|
2
|
-
_VERSION = '1.2.1',
|
|
3
|
-
_DESCRIPTION = 'semver for Lua',
|
|
4
|
-
_URL = 'https://github.com/kikito/semver.lua',
|
|
5
|
-
_LICENSE = [[
|
|
6
|
-
MIT LICENSE
|
|
7
|
-
|
|
8
|
-
Copyright (c) 2015 Enrique García Cota
|
|
9
|
-
|
|
10
|
-
Permission is hereby granted, free of charge, to any person obtaining a
|
|
11
|
-
copy of tother software and associated documentation files (the
|
|
12
|
-
"Software"), to deal in the Software without restriction, including
|
|
13
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
|
14
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
|
15
|
-
permit persons to whom the Software is furnished to do so, subject to
|
|
16
|
-
the following conditions:
|
|
17
|
-
|
|
18
|
-
The above copyright notice and tother permission notice shall be included
|
|
19
|
-
in all copies or substantial portions of the Software.
|
|
20
|
-
|
|
21
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
22
|
-
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
23
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
24
|
-
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
25
|
-
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
26
|
-
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
27
|
-
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
28
|
-
]]
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
local function checkPositiveInteger(number, name)
|
|
32
|
-
assert(number >= 0, name .. ' must be a valid positive number')
|
|
33
|
-
assert(math.floor(number) == number, name .. ' must be an integer')
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
local function present(value)
|
|
37
|
-
return value and value ~= ''
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
local function splitByDot(str)
|
|
42
|
-
str = str or ""
|
|
43
|
-
local t, count = {}, 0
|
|
44
|
-
str:gsub("([^%.]+)", function(c)
|
|
45
|
-
count = count + 1
|
|
46
|
-
t[count] = c
|
|
47
|
-
end)
|
|
48
|
-
return t
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
local function parsePrereleaseAndBuildWithSign(str)
|
|
52
|
-
local prereleaseWithSign, buildWithSign = str:match("^(-[^+]+)(+.+)$")
|
|
53
|
-
if not (prereleaseWithSign and buildWithSign) then
|
|
54
|
-
prereleaseWithSign = str:match("^(-.+)$")
|
|
55
|
-
buildWithSign = str:match("^(+.+)$")
|
|
56
|
-
end
|
|
57
|
-
assert(prereleaseWithSign or buildWithSign, ("The parameter %q must begin with + or - to denote a prerelease or a build"):format(str))
|
|
58
|
-
return prereleaseWithSign, buildWithSign
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
local function parsePrerelease(prereleaseWithSign)
|
|
62
|
-
if prereleaseWithSign then
|
|
63
|
-
local prerelease = prereleaseWithSign:match("^-(%w[%.%w-]*)$")
|
|
64
|
-
assert(prerelease, ("The prerelease %q is not a slash followed by alphanumerics, dots and slashes"):format(prereleaseWithSign))
|
|
65
|
-
return prerelease
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
local function parseBuild(buildWithSign)
|
|
70
|
-
if buildWithSign then
|
|
71
|
-
local build = buildWithSign:match("^%+(%w[%.%w-]*)$")
|
|
72
|
-
assert(build, ("The build %q is not a + sign followed by alphanumerics, dots and slashes"):format(buildWithSign))
|
|
73
|
-
return build
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
local function parsePrereleaseAndBuild(str)
|
|
78
|
-
if not present(str) then return nil, nil end
|
|
79
|
-
|
|
80
|
-
local prereleaseWithSign, buildWithSign = parsePrereleaseAndBuildWithSign(str)
|
|
81
|
-
|
|
82
|
-
local prerelease = parsePrerelease(prereleaseWithSign)
|
|
83
|
-
local build = parseBuild(buildWithSign)
|
|
84
|
-
|
|
85
|
-
return prerelease, build
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
local function parseVersion(str)
|
|
89
|
-
local sMajor, sMinor, sPatch, sPrereleaseAndBuild = str:match("^(%d+)%.?(%d*)%.?(%d*)(.-)$")
|
|
90
|
-
assert(type(sMajor) == 'string', ("Could not extract version number(s) from %q"):format(str))
|
|
91
|
-
local major, minor, patch = tonumber(sMajor), tonumber(sMinor), tonumber(sPatch)
|
|
92
|
-
local prerelease, build = parsePrereleaseAndBuild(sPrereleaseAndBuild)
|
|
93
|
-
return major, minor, patch, prerelease, build
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
local function compare(a,b)
|
|
98
|
-
return a == b and 0 or a < b and -1 or 1
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
local function compareIds(myId, otherId)
|
|
102
|
-
if myId == otherId then return 0
|
|
103
|
-
elseif not myId then return -1
|
|
104
|
-
elseif not otherId then return 1
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
local selfNumber, otherNumber = tonumber(myId), tonumber(otherId)
|
|
108
|
-
|
|
109
|
-
if selfNumber and otherNumber then
|
|
110
|
-
return compare(selfNumber, otherNumber)
|
|
111
|
-
elseif selfNumber then
|
|
112
|
-
return -1
|
|
113
|
-
elseif otherNumber then
|
|
114
|
-
return 1
|
|
115
|
-
else
|
|
116
|
-
return compare(myId, otherId)
|
|
117
|
-
end
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
local function smallerIdList(myIds, otherIds)
|
|
121
|
-
local myLength = #myIds
|
|
122
|
-
local comparison
|
|
123
|
-
|
|
124
|
-
for i=1, myLength do
|
|
125
|
-
comparison = compareIds(myIds[i], otherIds[i])
|
|
126
|
-
if comparison ~= 0 then
|
|
127
|
-
return comparison == -1
|
|
128
|
-
end
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
return myLength < #otherIds
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
local function smallerPrerelease(mine, other)
|
|
135
|
-
if mine == other or not mine then return false
|
|
136
|
-
elseif not other then return true
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
return smallerIdList(splitByDot(mine), splitByDot(other))
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
local methods = {}
|
|
143
|
-
|
|
144
|
-
function methods:nextMajor()
|
|
145
|
-
return semver(self.major + 1, 0, 0)
|
|
146
|
-
end
|
|
147
|
-
function methods:nextMinor()
|
|
148
|
-
return semver(self.major, self.minor + 1, 0)
|
|
149
|
-
end
|
|
150
|
-
function methods:nextPatch()
|
|
151
|
-
return semver(self.major, self.minor, self.patch + 1)
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
local mt = { __index = methods }
|
|
155
|
-
function mt:__eq(other)
|
|
156
|
-
return self.major == other.major and
|
|
157
|
-
self.minor == other.minor and
|
|
158
|
-
self.patch == other.patch and
|
|
159
|
-
self.prerelease == other.prerelease
|
|
160
|
-
end
|
|
161
|
-
function mt:__lt(other)
|
|
162
|
-
if self.major ~= other.major then return self.major < other.major end
|
|
163
|
-
if self.minor ~= other.minor then return self.minor < other.minor end
|
|
164
|
-
if self.patch ~= other.patch then return self.patch < other.patch end
|
|
165
|
-
return smallerPrerelease(self.prerelease, other.prerelease)
|
|
166
|
-
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
function mt:__pow(other)
|
|
170
|
-
if self.major == 0 then
|
|
171
|
-
return self == other
|
|
172
|
-
end
|
|
173
|
-
return self.major == other.major and
|
|
174
|
-
self.minor <= other.minor
|
|
175
|
-
end
|
|
176
|
-
function mt:__tostring()
|
|
177
|
-
local buffer = { ("%d.%d.%d"):format(self.major, self.minor, self.patch) }
|
|
178
|
-
if self.prerelease then table.insert(buffer, "-" .. self.prerelease) end
|
|
179
|
-
if self.build then table.insert(buffer, "+" .. self.build) end
|
|
180
|
-
return table.concat(buffer)
|
|
181
|
-
end
|
|
182
|
-
|
|
183
|
-
local function new(major, minor, patch, prerelease, build)
|
|
184
|
-
assert(major, "At least one parameter is needed")
|
|
185
|
-
|
|
186
|
-
if type(major) == 'string' then
|
|
187
|
-
major,minor,patch,prerelease,build = parseVersion(major)
|
|
188
|
-
end
|
|
189
|
-
patch = patch or 0
|
|
190
|
-
minor = minor or 0
|
|
191
|
-
|
|
192
|
-
checkPositiveInteger(major, "major")
|
|
193
|
-
checkPositiveInteger(minor, "minor")
|
|
194
|
-
checkPositiveInteger(patch, "patch")
|
|
195
|
-
|
|
196
|
-
local result = {major=major, minor=minor, patch=patch, prerelease=prerelease, build=build}
|
|
197
|
-
return setmetatable(result, mt)
|
|
198
|
-
end
|
|
199
|
-
|
|
200
|
-
setmetatable(semver, { __call = function(_, ...) return new(...) end })
|
|
201
|
-
semver._VERSION= semver(semver._VERSION)
|
|
202
|
-
|
|
203
|
-
local band, bor, lshift
|
|
204
|
-
= bit32.band, bit32.bor, bit32.lshift
|
|
205
|
-
local type, setmetatable, ipairs, select
|
|
206
|
-
= type, setmetatable, ipairs, select
|
|
207
|
-
local unpack, tonumber, error
|
|
208
|
-
= unpack, tonumber, error
|
|
209
|
-
local strsub, strbyte, strchar, gmatch, gsub
|
|
210
|
-
= string.sub, string.byte, string.char, string.gmatch, string.gsub
|
|
211
|
-
local strmatch, strfind, strformat
|
|
212
|
-
= string.match, string.find, string.format
|
|
213
|
-
local tinsert, tremove, tconcat
|
|
214
|
-
= table.insert, table.remove, table.concat
|
|
215
|
-
local max, min, floor, ceil, abs
|
|
216
|
-
= math.max, math.min, math.floor, math.ceil, math.abs
|
|
217
|
-
local clock = os.clock
|
|
218
|
-
|
|
219
|
-
local percentEncode_pattern = '[^A-Za-z0-9%-=;\',./~!@#$%&*%(%)_%+ %?]'
|
|
220
|
-
local function percentEncode_replace(v)
|
|
221
|
-
return strformat('%%%02X', strbyte(v))
|
|
222
|
-
end
|
|
223
|
-
|
|
224
|
-
local function indexOf(a, b, start)
|
|
225
|
-
if (#b == 0) then
|
|
226
|
-
return nil
|
|
227
|
-
end
|
|
228
|
-
return strfind(a, b, start, true)
|
|
229
|
-
end
|
|
230
|
-
|
|
231
|
-
local htmlEncode_pattern = '[&<>\n]'
|
|
232
|
-
local htmlEncode_replace = {
|
|
233
|
-
['&'] = '&', ['<'] = '<', ['>'] = '>', ['\n'] = '¶<br>'
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
local diff_main,
|
|
237
|
-
diff_cleanupSemantic,
|
|
238
|
-
diff_cleanupEfficiency,
|
|
239
|
-
diff_levenshtein,
|
|
240
|
-
diff_prettyHtml
|
|
241
|
-
|
|
242
|
-
local match_main
|
|
243
|
-
|
|
244
|
-
local patch_make,
|
|
245
|
-
patch_toText,
|
|
246
|
-
patch_fromText,
|
|
247
|
-
patch_apply
|
|
248
|
-
|
|
249
|
-
local DIFF_DELETE = -1
|
|
250
|
-
local DIFF_INSERT = 1
|
|
251
|
-
local DIFF_EQUAL = 0
|
|
252
|
-
|
|
253
|
-
local Diff_Timeout = 1.0
|
|
254
|
-
local Diff_EditCost = 4
|
|
255
|
-
local Match_Threshold = 0.5
|
|
256
|
-
local Match_Distance = 1000
|
|
257
|
-
local Patch_DeleteThreshold = 0.5
|
|
258
|
-
local Patch_Margin = 4
|
|
259
|
-
local Match_MaxBits = 32
|
|
260
|
-
|
|
261
|
-
function settings(new)
|
|
262
|
-
if new then
|
|
263
|
-
Diff_Timeout = new.Diff_Timeout or Diff_Timeout
|
|
264
|
-
Diff_EditCost = new.Diff_EditCost or Diff_EditCost
|
|
265
|
-
Match_Threshold = new.Match_Threshold or Match_Threshold
|
|
266
|
-
Match_Distance = new.Match_Distance or Match_Distance
|
|
267
|
-
Patch_DeleteThreshold = new.Patch_DeleteThreshold or Patch_DeleteThreshold
|
|
268
|
-
Patch_Margin = new.Patch_Margin or Patch_Margin
|
|
269
|
-
Match_MaxBits = new.Match_MaxBits or Match_MaxBits
|
|
270
|
-
else
|
|
271
|
-
return {
|
|
272
|
-
Diff_Timeout = Diff_Timeout;
|
|
273
|
-
Diff_EditCost = Diff_EditCost;
|
|
274
|
-
Match_Threshold = Match_Threshold;
|
|
275
|
-
Match_Distance = Match_Distance;
|
|
276
|
-
Patch_DeleteThreshold = Patch_DeleteThreshold;
|
|
277
|
-
Patch_Margin = Patch_Margin;
|
|
278
|
-
Match_MaxBits = Match_MaxBits;
|
|
279
|
-
}
|
|
280
|
-
end
|
|
281
|
-
end
|
|
282
|
-
|
|
283
|
-
local _diff_compute,
|
|
284
|
-
_diff_bisect,
|
|
285
|
-
_diff_halfMatchI,
|
|
286
|
-
_diff_halfMatch,
|
|
287
|
-
_diff_cleanupSemanticScore,
|
|
288
|
-
_diff_cleanupSemanticLossless,
|
|
289
|
-
_diff_cleanupMerge,
|
|
290
|
-
_diff_commonPrefix,
|
|
291
|
-
_diff_commonSuffix,
|
|
292
|
-
_diff_commonOverlap,
|
|
293
|
-
_diff_xIndex,
|
|
294
|
-
_diff_text1,
|
|
295
|
-
_diff_text2,
|
|
296
|
-
_diff_toDelta,
|
|
297
|
-
_diff_fromDelta
|
|
298
|
-
|
|
299
|
-
function diff_main(text1, text2, opt_checklines, opt_deadline)
|
|
300
|
-
if opt_deadline == nil then
|
|
301
|
-
if Diff_Timeout <= 0 then
|
|
302
|
-
opt_deadline = 2 ^ 31
|
|
303
|
-
else
|
|
304
|
-
opt_deadline = clock() + Diff_Timeout
|
|
305
|
-
end
|
|
306
|
-
end
|
|
307
|
-
local deadline = opt_deadline
|
|
308
|
-
|
|
309
|
-
if text1 == nil or text1 == nil then
|
|
310
|
-
error('Null inputs. (diff_main)')
|
|
311
|
-
end
|
|
312
|
-
|
|
313
|
-
if text1 == text2 then
|
|
314
|
-
if #text1 > 0 then
|
|
315
|
-
return {{DIFF_EQUAL, text1}}
|
|
316
|
-
end
|
|
317
|
-
return {}
|
|
318
|
-
end
|
|
319
|
-
|
|
320
|
-
local checklines = false
|
|
321
|
-
|
|
322
|
-
local commonlength = _diff_commonPrefix(text1, text2)
|
|
323
|
-
local commonprefix
|
|
324
|
-
if commonlength > 0 then
|
|
325
|
-
commonprefix = strsub(text1, 1, commonlength)
|
|
326
|
-
text1 = strsub(text1, commonlength + 1)
|
|
327
|
-
text2 = strsub(text2, commonlength + 1)
|
|
328
|
-
end
|
|
329
|
-
|
|
330
|
-
commonlength = _diff_commonSuffix(text1, text2)
|
|
331
|
-
local commonsuffix
|
|
332
|
-
if commonlength > 0 then
|
|
333
|
-
commonsuffix = strsub(text1, -commonlength)
|
|
334
|
-
text1 = strsub(text1, 1, -commonlength - 1)
|
|
335
|
-
text2 = strsub(text2, 1, -commonlength - 1)
|
|
336
|
-
end
|
|
337
|
-
|
|
338
|
-
local diffs = _diff_compute(text1, text2, checklines, deadline)
|
|
339
|
-
|
|
340
|
-
if commonprefix then
|
|
341
|
-
tinsert(diffs, 1, {DIFF_EQUAL, commonprefix})
|
|
342
|
-
end
|
|
343
|
-
if commonsuffix then
|
|
344
|
-
diffs[#diffs + 1] = {DIFF_EQUAL, commonsuffix}
|
|
345
|
-
end
|
|
346
|
-
|
|
347
|
-
_diff_cleanupMerge(diffs)
|
|
348
|
-
return diffs
|
|
349
|
-
end
|
|
350
|
-
|
|
351
|
-
function diff_cleanupSemantic(diffs)
|
|
352
|
-
local changes = false
|
|
353
|
-
local equalities = {}
|
|
354
|
-
local equalitiesLength = 0
|
|
355
|
-
local lastEquality = nil
|
|
356
|
-
local pointer = 1
|
|
357
|
-
local length_insertions1 = 0
|
|
358
|
-
local length_deletions1 = 0
|
|
359
|
-
local length_insertions2 = 0
|
|
360
|
-
local length_deletions2 = 0
|
|
361
|
-
|
|
362
|
-
while diffs[pointer] do
|
|
363
|
-
if diffs[pointer][1] == DIFF_EQUAL then
|
|
364
|
-
equalitiesLength = equalitiesLength + 1
|
|
365
|
-
equalities[equalitiesLength] = pointer
|
|
366
|
-
length_insertions1 = length_insertions2
|
|
367
|
-
length_deletions1 = length_deletions2
|
|
368
|
-
length_insertions2 = 0
|
|
369
|
-
length_deletions2 = 0
|
|
370
|
-
lastEquality = diffs[pointer][2]
|
|
371
|
-
else
|
|
372
|
-
if diffs[pointer][1] == DIFF_INSERT then
|
|
373
|
-
length_insertions2 = length_insertions2 + #(diffs[pointer][2])
|
|
374
|
-
else
|
|
375
|
-
length_deletions2 = length_deletions2 + #(diffs[pointer][2])
|
|
376
|
-
end
|
|
377
|
-
if lastEquality
|
|
378
|
-
and (#lastEquality <= max(length_insertions1, length_deletions1))
|
|
379
|
-
and (#lastEquality <= max(length_insertions2, length_deletions2)) then
|
|
380
|
-
tinsert(diffs, equalities[equalitiesLength],
|
|
381
|
-
{DIFF_DELETE, lastEquality})
|
|
382
|
-
diffs[equalities[equalitiesLength] + 1][1] = DIFF_INSERT
|
|
383
|
-
equalitiesLength = equalitiesLength - 1
|
|
384
|
-
equalitiesLength = equalitiesLength - 1
|
|
385
|
-
pointer = (equalitiesLength > 0) and equalities[equalitiesLength] or 0
|
|
386
|
-
length_insertions1, length_deletions1 = 0, 0
|
|
387
|
-
length_insertions2, length_deletions2 = 0, 0
|
|
388
|
-
lastEquality = nil
|
|
389
|
-
changes = true
|
|
390
|
-
end
|
|
391
|
-
end
|
|
392
|
-
pointer = pointer + 1
|
|
393
|
-
end
|
|
394
|
-
|
|
395
|
-
if changes then
|
|
396
|
-
_diff_cleanupMerge(diffs)
|
|
397
|
-
end
|
|
398
|
-
_diff_cleanupSemanticLossless(diffs)
|
|
399
|
-
|
|
400
|
-
pointer = 2
|
|
401
|
-
while diffs[pointer] do
|
|
402
|
-
if (diffs[pointer - 1][1] == DIFF_DELETE and
|
|
403
|
-
diffs[pointer][1] == DIFF_INSERT) then
|
|
404
|
-
local deletion = diffs[pointer - 1][2]
|
|
405
|
-
local insertion = diffs[pointer][2]
|
|
406
|
-
local overlap_length1 = _diff_commonOverlap(deletion, insertion)
|
|
407
|
-
local overlap_length2 = _diff_commonOverlap(insertion, deletion)
|
|
408
|
-
if (overlap_length1 >= overlap_length2) then
|
|
409
|
-
if (overlap_length1 >= #deletion / 2 or
|
|
410
|
-
overlap_length1 >= #insertion / 2) then
|
|
411
|
-
tinsert(diffs, pointer,
|
|
412
|
-
{DIFF_EQUAL, strsub(insertion, 1, overlap_length1)})
|
|
413
|
-
diffs[pointer - 1][2] =
|
|
414
|
-
strsub(deletion, 1, #deletion - overlap_length1)
|
|
415
|
-
diffs[pointer + 1][2] = strsub(insertion, overlap_length1 + 1)
|
|
416
|
-
pointer = pointer + 1
|
|
417
|
-
end
|
|
418
|
-
else
|
|
419
|
-
if (overlap_length2 >= #deletion / 2 or
|
|
420
|
-
overlap_length2 >= #insertion / 2) then
|
|
421
|
-
tinsert(diffs, pointer,
|
|
422
|
-
{DIFF_EQUAL, strsub(deletion, 1, overlap_length2)})
|
|
423
|
-
diffs[pointer - 1] = {DIFF_INSERT,
|
|
424
|
-
strsub(insertion, 1, #insertion - overlap_length2)}
|
|
425
|
-
diffs[pointer + 1] = {DIFF_DELETE,
|
|
426
|
-
strsub(deletion, overlap_length2 + 1)}
|
|
427
|
-
pointer = pointer + 1
|
|
428
|
-
end
|
|
429
|
-
end
|
|
430
|
-
pointer = pointer + 1
|
|
431
|
-
end
|
|
432
|
-
pointer = pointer + 1
|
|
433
|
-
end
|
|
434
|
-
end
|
|
435
|
-
|
|
436
|
-
function diff_cleanupEfficiency(diffs)
|
|
437
|
-
local changes = false
|
|
438
|
-
local equalities = {}
|
|
439
|
-
local equalitiesLength = 0
|
|
440
|
-
local lastEquality = nil
|
|
441
|
-
local pointer = 1
|
|
442
|
-
local pre_ins = 0
|
|
443
|
-
local pre_del = 0
|
|
444
|
-
local post_ins = 0
|
|
445
|
-
local post_del = 0
|
|
446
|
-
|
|
447
|
-
while diffs[pointer] do
|
|
448
|
-
if diffs[pointer][1] == DIFF_EQUAL then
|
|
449
|
-
local diffText = diffs[pointer][2]
|
|
450
|
-
if (#diffText < Diff_EditCost) and (post_ins == 1 or post_del == 1) then
|
|
451
|
-
equalitiesLength = equalitiesLength + 1
|
|
452
|
-
equalities[equalitiesLength] = pointer
|
|
453
|
-
pre_ins, pre_del = post_ins, post_del
|
|
454
|
-
lastEquality = diffText
|
|
455
|
-
else
|
|
456
|
-
equalitiesLength = 0
|
|
457
|
-
lastEquality = nil
|
|
458
|
-
end
|
|
459
|
-
post_ins, post_del = 0, 0
|
|
460
|
-
else
|
|
461
|
-
if diffs[pointer][1] == DIFF_DELETE then
|
|
462
|
-
post_del = 1
|
|
463
|
-
else
|
|
464
|
-
post_ins = 1
|
|
465
|
-
end
|
|
466
|
-
if lastEquality and (
|
|
467
|
-
(pre_ins+pre_del+post_ins+post_del == 4)
|
|
468
|
-
or
|
|
469
|
-
(
|
|
470
|
-
(#lastEquality < Diff_EditCost / 2)
|
|
471
|
-
and
|
|
472
|
-
(pre_ins+pre_del+post_ins+post_del == 3)
|
|
473
|
-
)) then
|
|
474
|
-
tinsert(diffs, equalities[equalitiesLength],
|
|
475
|
-
{DIFF_DELETE, lastEquality})
|
|
476
|
-
diffs[equalities[equalitiesLength] + 1][1] = DIFF_INSERT
|
|
477
|
-
equalitiesLength = equalitiesLength - 1
|
|
478
|
-
lastEquality = nil
|
|
479
|
-
if (pre_ins == 1) and (pre_del == 1) then
|
|
480
|
-
post_ins, post_del = 1, 1
|
|
481
|
-
equalitiesLength = 0
|
|
482
|
-
else
|
|
483
|
-
equalitiesLength = equalitiesLength - 1
|
|
484
|
-
pointer = (equalitiesLength > 0) and equalities[equalitiesLength] or 0
|
|
485
|
-
post_ins, post_del = 0, 0
|
|
486
|
-
end
|
|
487
|
-
changes = true
|
|
488
|
-
end
|
|
489
|
-
end
|
|
490
|
-
pointer = pointer + 1
|
|
491
|
-
end
|
|
492
|
-
|
|
493
|
-
if changes then
|
|
494
|
-
_diff_cleanupMerge(diffs)
|
|
495
|
-
end
|
|
496
|
-
end
|
|
497
|
-
|
|
498
|
-
function diff_levenshtein(diffs)
|
|
499
|
-
local levenshtein = 0
|
|
500
|
-
local insertions, deletions = 0, 0
|
|
501
|
-
for x, diff in ipairs(diffs) do
|
|
502
|
-
local op, data = diff[1], diff[2]
|
|
503
|
-
if (op == DIFF_INSERT) then
|
|
504
|
-
insertions = insertions + #data
|
|
505
|
-
elseif (op == DIFF_DELETE) then
|
|
506
|
-
deletions = deletions + #data
|
|
507
|
-
elseif (op == DIFF_EQUAL) then
|
|
508
|
-
levenshtein = levenshtein + max(insertions, deletions)
|
|
509
|
-
insertions = 0
|
|
510
|
-
deletions = 0
|
|
511
|
-
end
|
|
512
|
-
end
|
|
513
|
-
levenshtein = levenshtein + max(insertions, deletions)
|
|
514
|
-
return levenshtein
|
|
515
|
-
end
|
|
516
|
-
|
|
517
|
-
function diff_prettyHtml(diffs)
|
|
518
|
-
local html = {}
|
|
519
|
-
for x, diff in ipairs(diffs) do
|
|
520
|
-
local op = diff[1]
|
|
521
|
-
local data = diff[2]
|
|
522
|
-
local text = gsub(data, htmlEncode_pattern, htmlEncode_replace)
|
|
523
|
-
if op == DIFF_INSERT then
|
|
524
|
-
html[x] = '<ins style="background:#e6ffe6;">' .. text .. '</ins>'
|
|
525
|
-
elseif op == DIFF_DELETE then
|
|
526
|
-
html[x] = '<del style="background:#ffe6e6;">' .. text .. '</del>'
|
|
527
|
-
elseif op == DIFF_EQUAL then
|
|
528
|
-
html[x] = '<span>' .. text .. '</span>'
|
|
529
|
-
end
|
|
530
|
-
end
|
|
531
|
-
return tconcat(html)
|
|
532
|
-
end
|
|
533
|
-
|
|
534
|
-
function _diff_compute(text1, text2, checklines, deadline)
|
|
535
|
-
if #text1 == 0 then
|
|
536
|
-
return {{DIFF_INSERT, text2}}
|
|
537
|
-
end
|
|
538
|
-
|
|
539
|
-
if #text2 == 0 then
|
|
540
|
-
return {{DIFF_DELETE, text1}}
|
|
541
|
-
end
|
|
542
|
-
|
|
543
|
-
local diffs
|
|
544
|
-
|
|
545
|
-
local longtext = (#text1 > #text2) and text1 or text2
|
|
546
|
-
local shorttext = (#text1 > #text2) and text2 or text1
|
|
547
|
-
local i = indexOf(longtext, shorttext)
|
|
548
|
-
|
|
549
|
-
if i ~= nil then
|
|
550
|
-
diffs = {
|
|
551
|
-
{DIFF_INSERT, strsub(longtext, 1, i - 1)},
|
|
552
|
-
{DIFF_EQUAL, shorttext},
|
|
553
|
-
{DIFF_INSERT, strsub(longtext, i + #shorttext)}
|
|
554
|
-
}
|
|
555
|
-
if #text1 > #text2 then
|
|
556
|
-
diffs[1][1], diffs[3][1] = DIFF_DELETE, DIFF_DELETE
|
|
557
|
-
end
|
|
558
|
-
return diffs
|
|
559
|
-
end
|
|
560
|
-
|
|
561
|
-
if #shorttext == 1 then
|
|
562
|
-
return {{DIFF_DELETE, text1}, {DIFF_INSERT, text2}}
|
|
563
|
-
end
|
|
564
|
-
|
|
565
|
-
do
|
|
566
|
-
local
|
|
567
|
-
text1_a, text1_b,
|
|
568
|
-
text2_a, text2_b,
|
|
569
|
-
mid_common = _diff_halfMatch(text1, text2)
|
|
570
|
-
|
|
571
|
-
if text1_a then
|
|
572
|
-
local diffs_a = diff_main(text1_a, text2_a, checklines, deadline)
|
|
573
|
-
local diffs_b = diff_main(text1_b, text2_b, checklines, deadline)
|
|
574
|
-
local diffs_a_len = #diffs_a
|
|
575
|
-
diffs = diffs_a
|
|
576
|
-
diffs[diffs_a_len + 1] = {DIFF_EQUAL, mid_common}
|
|
577
|
-
for i, b_diff in ipairs(diffs_b) do
|
|
578
|
-
diffs[diffs_a_len + 1 + i] = b_diff
|
|
579
|
-
end
|
|
580
|
-
return diffs
|
|
581
|
-
end
|
|
582
|
-
end
|
|
583
|
-
|
|
584
|
-
return _diff_bisect(text1, text2, deadline)
|
|
585
|
-
end
|
|
586
|
-
|
|
587
|
-
function _diff_bisect(text1, text2, deadline)
|
|
588
|
-
local text1_length = #text1
|
|
589
|
-
local text2_length = #text2
|
|
590
|
-
local _sub, _element
|
|
591
|
-
local max_d = ceil((text1_length + text2_length) / 2)
|
|
592
|
-
local v_offset = max_d
|
|
593
|
-
local v_length = 2 * max_d
|
|
594
|
-
local v1 = {}
|
|
595
|
-
local v2 = {}
|
|
596
|
-
for x = 0, v_length - 1 do
|
|
597
|
-
v1[x] = -1
|
|
598
|
-
v2[x] = -1
|
|
599
|
-
end
|
|
600
|
-
v1[v_offset + 1] = 0
|
|
601
|
-
v2[v_offset + 1] = 0
|
|
602
|
-
local delta = text1_length - text2_length
|
|
603
|
-
local front = (delta % 2 ~= 0)
|
|
604
|
-
local k1start = 0
|
|
605
|
-
local k1end = 0
|
|
606
|
-
local k2start = 0
|
|
607
|
-
local k2end = 0
|
|
608
|
-
for d = 0, max_d - 1 do
|
|
609
|
-
if clock() > deadline then
|
|
610
|
-
break
|
|
611
|
-
end
|
|
612
|
-
for k1 = -d + k1start, d - k1end, 2 do
|
|
613
|
-
local k1_offset = v_offset + k1
|
|
614
|
-
local x1
|
|
615
|
-
if (k1 == -d) or ((k1 ~= d) and
|
|
616
|
-
(v1[k1_offset - 1] < v1[k1_offset + 1])) then
|
|
617
|
-
x1 = v1[k1_offset + 1]
|
|
618
|
-
else
|
|
619
|
-
x1 = v1[k1_offset - 1] + 1
|
|
620
|
-
end
|
|
621
|
-
local y1 = x1 - k1
|
|
622
|
-
while (x1 <= text1_length) and (y1 <= text2_length)
|
|
623
|
-
and (strsub(text1, x1, x1) == strsub(text2, y1, y1)) do
|
|
624
|
-
x1 = x1 + 1
|
|
625
|
-
y1 = y1 + 1
|
|
626
|
-
end
|
|
627
|
-
v1[k1_offset] = x1
|
|
628
|
-
if x1 > text1_length + 1 then
|
|
629
|
-
k1end = k1end + 2
|
|
630
|
-
elseif y1 > text2_length + 1 then
|
|
631
|
-
k1start = k1start + 2
|
|
632
|
-
elseif front then
|
|
633
|
-
local k2_offset = v_offset + delta - k1
|
|
634
|
-
if k2_offset >= 0 and k2_offset < v_length and v2[k2_offset] ~= -1 then
|
|
635
|
-
local x2 = text1_length - v2[k2_offset] + 1
|
|
636
|
-
if x1 > x2 then
|
|
637
|
-
return _diff_bisectSplit(text1, text2, x1, y1, deadline)
|
|
638
|
-
end
|
|
639
|
-
end
|
|
640
|
-
end
|
|
641
|
-
end
|
|
642
|
-
|
|
643
|
-
for k2 = -d + k2start, d - k2end, 2 do
|
|
644
|
-
local k2_offset = v_offset + k2
|
|
645
|
-
local x2
|
|
646
|
-
if (k2 == -d) or ((k2 ~= d) and
|
|
647
|
-
(v2[k2_offset - 1] < v2[k2_offset + 1])) then
|
|
648
|
-
x2 = v2[k2_offset + 1]
|
|
649
|
-
else
|
|
650
|
-
x2 = v2[k2_offset - 1] + 1
|
|
651
|
-
end
|
|
652
|
-
local y2 = x2 - k2
|
|
653
|
-
while (x2 <= text1_length) and (y2 <= text2_length)
|
|
654
|
-
and (strsub(text1, -x2, -x2) == strsub(text2, -y2, -y2)) do
|
|
655
|
-
x2 = x2 + 1
|
|
656
|
-
y2 = y2 + 1
|
|
657
|
-
end
|
|
658
|
-
v2[k2_offset] = x2
|
|
659
|
-
if x2 > text1_length + 1 then
|
|
660
|
-
k2end = k2end + 2
|
|
661
|
-
elseif y2 > text2_length + 1 then
|
|
662
|
-
k2start = k2start + 2
|
|
663
|
-
elseif not front then
|
|
664
|
-
local k1_offset = v_offset + delta - k2
|
|
665
|
-
if k1_offset >= 0 and k1_offset < v_length and v1[k1_offset] ~= -1 then
|
|
666
|
-
local x1 = v1[k1_offset]
|
|
667
|
-
local y1 = v_offset + x1 - k1_offset
|
|
668
|
-
x2 = text1_length - x2 + 1
|
|
669
|
-
if x1 > x2 then
|
|
670
|
-
return _diff_bisectSplit(text1, text2, x1, y1, deadline)
|
|
671
|
-
end
|
|
672
|
-
end
|
|
673
|
-
end
|
|
674
|
-
end
|
|
675
|
-
end
|
|
676
|
-
return {{DIFF_DELETE, text1}, {DIFF_INSERT, text2}}
|
|
677
|
-
end
|
|
678
|
-
|
|
679
|
-
function _diff_bisectSplit(text1, text2, x, y, deadline)
|
|
680
|
-
local text1a = strsub(text1, 1, x - 1)
|
|
681
|
-
local text2a = strsub(text2, 1, y - 1)
|
|
682
|
-
local text1b = strsub(text1, x)
|
|
683
|
-
local text2b = strsub(text2, y)
|
|
684
|
-
|
|
685
|
-
local diffs = diff_main(text1a, text2a, false, deadline)
|
|
686
|
-
local diffsb = diff_main(text1b, text2b, false, deadline)
|
|
687
|
-
|
|
688
|
-
local diffs_len = #diffs
|
|
689
|
-
for i, v in ipairs(diffsb) do
|
|
690
|
-
diffs[diffs_len + i] = v
|
|
691
|
-
end
|
|
692
|
-
return diffs
|
|
693
|
-
end
|
|
694
|
-
|
|
695
|
-
function _diff_commonPrefix(text1, text2)
|
|
696
|
-
if (#text1 == 0) or (#text2 == 0) or (strbyte(text1, 1) ~= strbyte(text2, 1))
|
|
697
|
-
then
|
|
698
|
-
return 0
|
|
699
|
-
end
|
|
700
|
-
local pointermin = 1
|
|
701
|
-
local pointermax = min(#text1, #text2)
|
|
702
|
-
local pointermid = pointermax
|
|
703
|
-
local pointerstart = 1
|
|
704
|
-
while (pointermin < pointermid) do
|
|
705
|
-
if (strsub(text1, pointerstart, pointermid)
|
|
706
|
-
== strsub(text2, pointerstart, pointermid)) then
|
|
707
|
-
pointermin = pointermid
|
|
708
|
-
pointerstart = pointermin
|
|
709
|
-
else
|
|
710
|
-
pointermax = pointermid
|
|
711
|
-
end
|
|
712
|
-
pointermid = floor(pointermin + (pointermax - pointermin) / 2)
|
|
713
|
-
end
|
|
714
|
-
return pointermid
|
|
715
|
-
end
|
|
716
|
-
|
|
717
|
-
function _diff_commonSuffix(text1, text2)
|
|
718
|
-
if (#text1 == 0) or (#text2 == 0)
|
|
719
|
-
or (strbyte(text1, -1) ~= strbyte(text2, -1)) then
|
|
720
|
-
return 0
|
|
721
|
-
end
|
|
722
|
-
local pointermin = 1
|
|
723
|
-
local pointermax = min(#text1, #text2)
|
|
724
|
-
local pointermid = pointermax
|
|
725
|
-
local pointerend = 1
|
|
726
|
-
while (pointermin < pointermid) do
|
|
727
|
-
if (strsub(text1, -pointermid, -pointerend)
|
|
728
|
-
== strsub(text2, -pointermid, -pointerend)) then
|
|
729
|
-
pointermin = pointermid
|
|
730
|
-
pointerend = pointermin
|
|
731
|
-
else
|
|
732
|
-
pointermax = pointermid
|
|
733
|
-
end
|
|
734
|
-
pointermid = floor(pointermin + (pointermax - pointermin) / 2)
|
|
735
|
-
end
|
|
736
|
-
return pointermid
|
|
737
|
-
end
|
|
738
|
-
|
|
739
|
-
function _diff_commonOverlap(text1, text2)
|
|
740
|
-
local text1_length = #text1
|
|
741
|
-
local text2_length = #text2
|
|
742
|
-
if text1_length == 0 or text2_length == 0 then
|
|
743
|
-
return 0
|
|
744
|
-
end
|
|
745
|
-
if text1_length > text2_length then
|
|
746
|
-
text1 = strsub(text1, text1_length - text2_length + 1)
|
|
747
|
-
elseif text1_length < text2_length then
|
|
748
|
-
text2 = strsub(text2, 1, text1_length)
|
|
749
|
-
end
|
|
750
|
-
local text_length = min(text1_length, text2_length)
|
|
751
|
-
if text1 == text2 then
|
|
752
|
-
return text_length
|
|
753
|
-
end
|
|
754
|
-
|
|
755
|
-
local best = 0
|
|
756
|
-
local length = 1
|
|
757
|
-
while true do
|
|
758
|
-
local pattern = strsub(text1, text_length - length + 1)
|
|
759
|
-
local found = strfind(text2, pattern, 1, true)
|
|
760
|
-
if found == nil then
|
|
761
|
-
return best
|
|
762
|
-
end
|
|
763
|
-
length = length + found - 1
|
|
764
|
-
if found == 1 or strsub(text1, text_length - length + 1) ==
|
|
765
|
-
strsub(text2, 1, length) then
|
|
766
|
-
best = length
|
|
767
|
-
length = length + 1
|
|
768
|
-
end
|
|
769
|
-
end
|
|
770
|
-
end
|
|
771
|
-
|
|
772
|
-
function _diff_halfMatchI(longtext, shorttext, i)
|
|
773
|
-
local seed = strsub(longtext, i, i + floor(#longtext / 4))
|
|
774
|
-
local j = 0
|
|
775
|
-
local best_common = ''
|
|
776
|
-
local best_longtext_a, best_longtext_b, best_shorttext_a, best_shorttext_b
|
|
777
|
-
while true do
|
|
778
|
-
j = indexOf(shorttext, seed, j + 1)
|
|
779
|
-
if (j == nil) then
|
|
780
|
-
break
|
|
781
|
-
end
|
|
782
|
-
local prefixLength = _diff_commonPrefix(strsub(longtext, i),
|
|
783
|
-
strsub(shorttext, j))
|
|
784
|
-
local suffixLength = _diff_commonSuffix(strsub(longtext, 1, i - 1),
|
|
785
|
-
strsub(shorttext, 1, j - 1))
|
|
786
|
-
if #best_common < suffixLength + prefixLength then
|
|
787
|
-
best_common = strsub(shorttext, j - suffixLength, j - 1)
|
|
788
|
-
.. strsub(shorttext, j, j + prefixLength - 1)
|
|
789
|
-
best_longtext_a = strsub(longtext, 1, i - suffixLength - 1)
|
|
790
|
-
best_longtext_b = strsub(longtext, i + prefixLength)
|
|
791
|
-
best_shorttext_a = strsub(shorttext, 1, j - suffixLength - 1)
|
|
792
|
-
best_shorttext_b = strsub(shorttext, j + prefixLength)
|
|
793
|
-
end
|
|
794
|
-
end
|
|
795
|
-
if #best_common * 2 >= #longtext then
|
|
796
|
-
return {best_longtext_a, best_longtext_b,
|
|
797
|
-
best_shorttext_a, best_shorttext_b, best_common}
|
|
798
|
-
else
|
|
799
|
-
return nil
|
|
800
|
-
end
|
|
801
|
-
end
|
|
802
|
-
|
|
803
|
-
function _diff_halfMatch(text1, text2)
|
|
804
|
-
if Diff_Timeout <= 0 then
|
|
805
|
-
return nil
|
|
806
|
-
end
|
|
807
|
-
local longtext = (#text1 > #text2) and text1 or text2
|
|
808
|
-
local shorttext = (#text1 > #text2) and text2 or text1
|
|
809
|
-
if (#longtext < 4) or (#shorttext * 2 < #longtext) then
|
|
810
|
-
return nil
|
|
811
|
-
end
|
|
812
|
-
|
|
813
|
-
local hm1 = _diff_halfMatchI(longtext, shorttext, ceil(#longtext / 4))
|
|
814
|
-
local hm2 = _diff_halfMatchI(longtext, shorttext, ceil(#longtext / 2))
|
|
815
|
-
local hm
|
|
816
|
-
if not hm1 and not hm2 then
|
|
817
|
-
return nil
|
|
818
|
-
elseif not hm2 then
|
|
819
|
-
hm = hm1
|
|
820
|
-
elseif not hm1 then
|
|
821
|
-
hm = hm2
|
|
822
|
-
else
|
|
823
|
-
hm = (#hm1[5] > #hm2[5]) and hm1 or hm2
|
|
824
|
-
end
|
|
825
|
-
|
|
826
|
-
local text1_a, text1_b, text2_a, text2_b
|
|
827
|
-
if (#text1 > #text2) then
|
|
828
|
-
text1_a, text1_b = hm[1], hm[2]
|
|
829
|
-
text2_a, text2_b = hm[3], hm[4]
|
|
830
|
-
else
|
|
831
|
-
text2_a, text2_b = hm[1], hm[2]
|
|
832
|
-
text1_a, text1_b = hm[3], hm[4]
|
|
833
|
-
end
|
|
834
|
-
local mid_common = hm[5]
|
|
835
|
-
return text1_a, text1_b, text2_a, text2_b, mid_common
|
|
836
|
-
end
|
|
837
|
-
|
|
838
|
-
function _diff_cleanupSemanticScore(one, two)
|
|
839
|
-
if (#one == 0) or (#two == 0) then
|
|
840
|
-
return 6
|
|
841
|
-
end
|
|
842
|
-
|
|
843
|
-
local char1 = strsub(one, -1)
|
|
844
|
-
local char2 = strsub(two, 1, 1)
|
|
845
|
-
local nonAlphaNumeric1 = strmatch(char1, '%W')
|
|
846
|
-
local nonAlphaNumeric2 = strmatch(char2, '%W')
|
|
847
|
-
local whitespace1 = nonAlphaNumeric1 and strmatch(char1, '%s')
|
|
848
|
-
local whitespace2 = nonAlphaNumeric2 and strmatch(char2, '%s')
|
|
849
|
-
local lineBreak1 = whitespace1 and strmatch(char1, '%c')
|
|
850
|
-
local lineBreak2 = whitespace2 and strmatch(char2, '%c')
|
|
851
|
-
local blankLine1 = lineBreak1 and strmatch(one, '\n\r?\n$')
|
|
852
|
-
local blankLine2 = lineBreak2 and strmatch(two, '^\r?\n\r?\n')
|
|
853
|
-
|
|
854
|
-
if blankLine1 or blankLine2 then
|
|
855
|
-
return 5
|
|
856
|
-
elseif lineBreak1 or lineBreak2 then
|
|
857
|
-
return 4
|
|
858
|
-
elseif nonAlphaNumeric1 and not whitespace1 and whitespace2 then
|
|
859
|
-
return 3
|
|
860
|
-
elseif whitespace1 or whitespace2 then
|
|
861
|
-
return 2
|
|
862
|
-
elseif nonAlphaNumeric1 or nonAlphaNumeric2 then
|
|
863
|
-
return 1
|
|
864
|
-
end
|
|
865
|
-
return 0
|
|
866
|
-
end
|
|
867
|
-
|
|
868
|
-
function _diff_cleanupSemanticLossless(diffs)
|
|
869
|
-
local pointer = 2
|
|
870
|
-
while diffs[pointer + 1] do
|
|
871
|
-
local prevDiff, nextDiff = diffs[pointer - 1], diffs[pointer + 1]
|
|
872
|
-
if (prevDiff[1] == DIFF_EQUAL) and (nextDiff[1] == DIFF_EQUAL) then
|
|
873
|
-
local diff = diffs[pointer]
|
|
874
|
-
|
|
875
|
-
local equality1 = prevDiff[2]
|
|
876
|
-
local edit = diff[2]
|
|
877
|
-
local equality2 = nextDiff[2]
|
|
878
|
-
|
|
879
|
-
local commonOffset = _diff_commonSuffix(equality1, edit)
|
|
880
|
-
if commonOffset > 0 then
|
|
881
|
-
local commonString = strsub(edit, -commonOffset)
|
|
882
|
-
equality1 = strsub(equality1, 1, -commonOffset - 1)
|
|
883
|
-
edit = commonString .. strsub(edit, 1, -commonOffset - 1)
|
|
884
|
-
equality2 = commonString .. equality2
|
|
885
|
-
end
|
|
886
|
-
|
|
887
|
-
local bestEquality1 = equality1
|
|
888
|
-
local bestEdit = edit
|
|
889
|
-
local bestEquality2 = equality2
|
|
890
|
-
local bestScore = _diff_cleanupSemanticScore(equality1, edit)
|
|
891
|
-
+ _diff_cleanupSemanticScore(edit, equality2)
|
|
892
|
-
|
|
893
|
-
while strbyte(edit, 1) == strbyte(equality2, 1) do
|
|
894
|
-
equality1 = equality1 .. strsub(edit, 1, 1)
|
|
895
|
-
edit = strsub(edit, 2) .. strsub(equality2, 1, 1)
|
|
896
|
-
equality2 = strsub(equality2, 2)
|
|
897
|
-
local score = _diff_cleanupSemanticScore(equality1, edit)
|
|
898
|
-
+ _diff_cleanupSemanticScore(edit, equality2)
|
|
899
|
-
if score >= bestScore then
|
|
900
|
-
bestScore = score
|
|
901
|
-
bestEquality1 = equality1
|
|
902
|
-
bestEdit = edit
|
|
903
|
-
bestEquality2 = equality2
|
|
904
|
-
end
|
|
905
|
-
end
|
|
906
|
-
if prevDiff[2] ~= bestEquality1 then
|
|
907
|
-
if #bestEquality1 > 0 then
|
|
908
|
-
diffs[pointer - 1][2] = bestEquality1
|
|
909
|
-
else
|
|
910
|
-
tremove(diffs, pointer - 1)
|
|
911
|
-
pointer = pointer - 1
|
|
912
|
-
end
|
|
913
|
-
diffs[pointer][2] = bestEdit
|
|
914
|
-
if #bestEquality2 > 0 then
|
|
915
|
-
diffs[pointer + 1][2] = bestEquality2
|
|
916
|
-
else
|
|
917
|
-
tremove(diffs, pointer + 1, 1)
|
|
918
|
-
pointer = pointer - 1
|
|
919
|
-
end
|
|
920
|
-
end
|
|
921
|
-
end
|
|
922
|
-
pointer = pointer + 1
|
|
923
|
-
end
|
|
924
|
-
end
|
|
925
|
-
|
|
926
|
-
function _diff_cleanupMerge(diffs)
|
|
927
|
-
diffs[#diffs + 1] = {DIFF_EQUAL, ''}
|
|
928
|
-
local pointer = 1
|
|
929
|
-
local count_delete, count_insert = 0, 0
|
|
930
|
-
local text_delete, text_insert = '', ''
|
|
931
|
-
local commonlength
|
|
932
|
-
while diffs[pointer] do
|
|
933
|
-
local diff_type = diffs[pointer][1]
|
|
934
|
-
if diff_type == DIFF_INSERT then
|
|
935
|
-
count_insert = count_insert + 1
|
|
936
|
-
text_insert = text_insert .. diffs[pointer][2]
|
|
937
|
-
pointer = pointer + 1
|
|
938
|
-
elseif diff_type == DIFF_DELETE then
|
|
939
|
-
count_delete = count_delete + 1
|
|
940
|
-
text_delete = text_delete .. diffs[pointer][2]
|
|
941
|
-
pointer = pointer + 1
|
|
942
|
-
elseif diff_type == DIFF_EQUAL then
|
|
943
|
-
if count_delete + count_insert > 1 then
|
|
944
|
-
if (count_delete > 0) and (count_insert > 0) then
|
|
945
|
-
commonlength = _diff_commonPrefix(text_insert, text_delete)
|
|
946
|
-
if commonlength > 0 then
|
|
947
|
-
local back_pointer = pointer - count_delete - count_insert
|
|
948
|
-
if (back_pointer > 1) and (diffs[back_pointer - 1][1] == DIFF_EQUAL)
|
|
949
|
-
then
|
|
950
|
-
diffs[back_pointer - 1][2] = diffs[back_pointer - 1][2]
|
|
951
|
-
.. strsub(text_insert, 1, commonlength)
|
|
952
|
-
else
|
|
953
|
-
tinsert(diffs, 1,
|
|
954
|
-
{DIFF_EQUAL, strsub(text_insert, 1, commonlength)})
|
|
955
|
-
pointer = pointer + 1
|
|
956
|
-
end
|
|
957
|
-
text_insert = strsub(text_insert, commonlength + 1)
|
|
958
|
-
text_delete = strsub(text_delete, commonlength + 1)
|
|
959
|
-
end
|
|
960
|
-
commonlength = _diff_commonSuffix(text_insert, text_delete)
|
|
961
|
-
if commonlength ~= 0 then
|
|
962
|
-
diffs[pointer][2] =
|
|
963
|
-
strsub(text_insert, -commonlength) .. diffs[pointer][2]
|
|
964
|
-
text_insert = strsub(text_insert, 1, -commonlength - 1)
|
|
965
|
-
text_delete = strsub(text_delete, 1, -commonlength - 1)
|
|
966
|
-
end
|
|
967
|
-
end
|
|
968
|
-
pointer = pointer - count_delete - count_insert
|
|
969
|
-
for i = 1, count_delete + count_insert do
|
|
970
|
-
tremove(diffs, pointer)
|
|
971
|
-
end
|
|
972
|
-
if #text_delete > 0 then
|
|
973
|
-
tinsert(diffs, pointer, {DIFF_DELETE, text_delete})
|
|
974
|
-
pointer = pointer + 1
|
|
975
|
-
end
|
|
976
|
-
if #text_insert > 0 then
|
|
977
|
-
tinsert(diffs, pointer, {DIFF_INSERT, text_insert})
|
|
978
|
-
pointer = pointer + 1
|
|
979
|
-
end
|
|
980
|
-
pointer = pointer + 1
|
|
981
|
-
elseif (pointer > 1) and (diffs[pointer - 1][1] == DIFF_EQUAL) then
|
|
982
|
-
diffs[pointer - 1][2] = diffs[pointer - 1][2] .. diffs[pointer][2]
|
|
983
|
-
tremove(diffs, pointer)
|
|
984
|
-
else
|
|
985
|
-
pointer = pointer + 1
|
|
986
|
-
end
|
|
987
|
-
count_insert, count_delete = 0, 0
|
|
988
|
-
text_delete, text_insert = '', ''
|
|
989
|
-
end
|
|
990
|
-
end
|
|
991
|
-
if diffs[#diffs][2] == '' then
|
|
992
|
-
diffs[#diffs] = nil
|
|
993
|
-
end
|
|
994
|
-
|
|
995
|
-
local changes = false
|
|
996
|
-
pointer = 2
|
|
997
|
-
while pointer < #diffs do
|
|
998
|
-
local prevDiff, nextDiff = diffs[pointer - 1], diffs[pointer + 1]
|
|
999
|
-
if (prevDiff[1] == DIFF_EQUAL) and (nextDiff[1] == DIFF_EQUAL) then
|
|
1000
|
-
local diff = diffs[pointer]
|
|
1001
|
-
local currentText = diff[2]
|
|
1002
|
-
local prevText = prevDiff[2]
|
|
1003
|
-
local nextText = nextDiff[2]
|
|
1004
|
-
if #prevText == 0 then
|
|
1005
|
-
tremove(diffs, pointer - 1)
|
|
1006
|
-
changes = true
|
|
1007
|
-
elseif strsub(currentText, -#prevText) == prevText then
|
|
1008
|
-
diff[2] = prevText .. strsub(currentText, 1, -#prevText - 1)
|
|
1009
|
-
nextDiff[2] = prevText .. nextDiff[2]
|
|
1010
|
-
tremove(diffs, pointer - 1)
|
|
1011
|
-
changes = true
|
|
1012
|
-
elseif strsub(currentText, 1, #nextText) == nextText then
|
|
1013
|
-
prevDiff[2] = prevText .. nextText
|
|
1014
|
-
diff[2] = strsub(currentText, #nextText + 1) .. nextText
|
|
1015
|
-
tremove(diffs, pointer + 1)
|
|
1016
|
-
changes = true
|
|
1017
|
-
end
|
|
1018
|
-
end
|
|
1019
|
-
pointer = pointer + 1
|
|
1020
|
-
end
|
|
1021
|
-
|
|
1022
|
-
if changes then
|
|
1023
|
-
return _diff_cleanupMerge(diffs)
|
|
1024
|
-
end
|
|
1025
|
-
end
|
|
1026
|
-
|
|
1027
|
-
function _diff_xIndex(diffs, loc)
|
|
1028
|
-
local chars1 = 1
|
|
1029
|
-
local chars2 = 1
|
|
1030
|
-
local last_chars1 = 1
|
|
1031
|
-
local last_chars2 = 1
|
|
1032
|
-
local x
|
|
1033
|
-
for _x, diff in ipairs(diffs) do
|
|
1034
|
-
x = _x
|
|
1035
|
-
if diff[1] ~= DIFF_INSERT then
|
|
1036
|
-
chars1 = chars1 + #diff[2]
|
|
1037
|
-
end
|
|
1038
|
-
if diff[1] ~= DIFF_DELETE then
|
|
1039
|
-
chars2 = chars2 + #diff[2]
|
|
1040
|
-
end
|
|
1041
|
-
if chars1 > loc then
|
|
1042
|
-
break
|
|
1043
|
-
end
|
|
1044
|
-
last_chars1 = chars1
|
|
1045
|
-
last_chars2 = chars2
|
|
1046
|
-
end
|
|
1047
|
-
if diffs[x + 1] and (diffs[x][1] == DIFF_DELETE) then
|
|
1048
|
-
return last_chars2
|
|
1049
|
-
end
|
|
1050
|
-
return last_chars2 + (loc - last_chars1)
|
|
1051
|
-
end
|
|
1052
|
-
|
|
1053
|
-
function _diff_text1(diffs)
|
|
1054
|
-
local text = {}
|
|
1055
|
-
for x, diff in ipairs(diffs) do
|
|
1056
|
-
if diff[1] ~= DIFF_INSERT then
|
|
1057
|
-
text[#text + 1] = diff[2]
|
|
1058
|
-
end
|
|
1059
|
-
end
|
|
1060
|
-
return tconcat(text)
|
|
1061
|
-
end
|
|
1062
|
-
|
|
1063
|
-
function _diff_text2(diffs)
|
|
1064
|
-
local text = {}
|
|
1065
|
-
for x, diff in ipairs(diffs) do
|
|
1066
|
-
if diff[1] ~= DIFF_DELETE then
|
|
1067
|
-
text[#text + 1] = diff[2]
|
|
1068
|
-
end
|
|
1069
|
-
end
|
|
1070
|
-
return tconcat(text)
|
|
1071
|
-
end
|
|
1072
|
-
|
|
1073
|
-
function _diff_toDelta(diffs)
|
|
1074
|
-
local text = {}
|
|
1075
|
-
for x, diff in ipairs(diffs) do
|
|
1076
|
-
local op, data = diff[1], diff[2]
|
|
1077
|
-
if op == DIFF_INSERT then
|
|
1078
|
-
text[x] = '+' .. gsub(data, percentEncode_pattern, percentEncode_replace)
|
|
1079
|
-
elseif op == DIFF_DELETE then
|
|
1080
|
-
text[x] = '-' .. #data
|
|
1081
|
-
elseif op == DIFF_EQUAL then
|
|
1082
|
-
text[x] = '=' .. #data
|
|
1083
|
-
end
|
|
1084
|
-
end
|
|
1085
|
-
return tconcat(text, '\t')
|
|
1086
|
-
end
|
|
1087
|
-
|
|
1088
|
-
function _diff_fromDelta(text1, delta)
|
|
1089
|
-
local diffs = {}
|
|
1090
|
-
local diffsLength = 0
|
|
1091
|
-
local pointer = 1
|
|
1092
|
-
for token in gmatch(delta, '[^\t]+') do
|
|
1093
|
-
local tokenchar, param = strsub(token, 1, 1), strsub(token, 2)
|
|
1094
|
-
if (tokenchar == '+') then
|
|
1095
|
-
local invalidDecode = false
|
|
1096
|
-
local decoded = gsub(param, '%%(.?.?)',
|
|
1097
|
-
function(c)
|
|
1098
|
-
local n = tonumber(c, 16)
|
|
1099
|
-
if (#c ~= 2) or (n == nil) then
|
|
1100
|
-
invalidDecode = true
|
|
1101
|
-
return ''
|
|
1102
|
-
end
|
|
1103
|
-
return strchar(n)
|
|
1104
|
-
end)
|
|
1105
|
-
if invalidDecode then
|
|
1106
|
-
error('Illegal escape in _diff_fromDelta: ' .. param)
|
|
1107
|
-
end
|
|
1108
|
-
diffsLength = diffsLength + 1
|
|
1109
|
-
diffs[diffsLength] = {DIFF_INSERT, decoded}
|
|
1110
|
-
elseif (tokenchar == '-') or (tokenchar == '=') then
|
|
1111
|
-
local n = tonumber(param)
|
|
1112
|
-
if (n == nil) or (n < 0) then
|
|
1113
|
-
error('Invalid number in _diff_fromDelta: ' .. param)
|
|
1114
|
-
end
|
|
1115
|
-
local text = strsub(text1, pointer, pointer + n - 1)
|
|
1116
|
-
pointer = pointer + n
|
|
1117
|
-
if (tokenchar == '=') then
|
|
1118
|
-
diffsLength = diffsLength + 1
|
|
1119
|
-
diffs[diffsLength] = {DIFF_EQUAL, text}
|
|
1120
|
-
else
|
|
1121
|
-
diffsLength = diffsLength + 1
|
|
1122
|
-
diffs[diffsLength] = {DIFF_DELETE, text}
|
|
1123
|
-
end
|
|
1124
|
-
else
|
|
1125
|
-
error('Invalid diff operation in _diff_fromDelta: ' .. token)
|
|
1126
|
-
end
|
|
1127
|
-
end
|
|
1128
|
-
if (pointer ~= #text1 + 1) then
|
|
1129
|
-
error('Delta length (' .. (pointer - 1)
|
|
1130
|
-
.. ') does not equal source text length (' .. #text1 .. ').')
|
|
1131
|
-
end
|
|
1132
|
-
return diffs
|
|
1133
|
-
end
|
|
1134
|
-
|
|
1135
|
-
local _match_bitap, _match_alphabet
|
|
1136
|
-
|
|
1137
|
-
function match_main(text, pattern, loc)
|
|
1138
|
-
if text == nil or pattern == nil or loc == nil then
|
|
1139
|
-
error('Null inputs. (match_main)')
|
|
1140
|
-
end
|
|
1141
|
-
|
|
1142
|
-
if text == pattern then
|
|
1143
|
-
return 1
|
|
1144
|
-
elseif #text == 0 then
|
|
1145
|
-
return -1
|
|
1146
|
-
end
|
|
1147
|
-
loc = max(1, min(loc, #text))
|
|
1148
|
-
if strsub(text, loc, loc + #pattern - 1) == pattern then
|
|
1149
|
-
return loc
|
|
1150
|
-
else
|
|
1151
|
-
return _match_bitap(text, pattern, loc)
|
|
1152
|
-
end
|
|
1153
|
-
end
|
|
1154
|
-
|
|
1155
|
-
function _match_alphabet(pattern)
|
|
1156
|
-
local s = {}
|
|
1157
|
-
local i = 0
|
|
1158
|
-
for c in gmatch(pattern, '.') do
|
|
1159
|
-
s[c] = bor(s[c] or 0, lshift(1, #pattern - i - 1))
|
|
1160
|
-
i = i + 1
|
|
1161
|
-
end
|
|
1162
|
-
return s
|
|
1163
|
-
end
|
|
1164
|
-
|
|
1165
|
-
function _match_bitap(text, pattern, loc)
|
|
1166
|
-
if #pattern > Match_MaxBits then
|
|
1167
|
-
error('Pattern too long.')
|
|
1168
|
-
end
|
|
1169
|
-
|
|
1170
|
-
local s = _match_alphabet(pattern)
|
|
1171
|
-
|
|
1172
|
-
local function _match_bitapScore(e, x)
|
|
1173
|
-
local accuracy = e / #pattern
|
|
1174
|
-
local proximity = abs(loc - x)
|
|
1175
|
-
if (Match_Distance == 0) then
|
|
1176
|
-
return (proximity == 0) and 1 or accuracy
|
|
1177
|
-
end
|
|
1178
|
-
return accuracy + (proximity / Match_Distance)
|
|
1179
|
-
end
|
|
1180
|
-
|
|
1181
|
-
local score_threshold = Match_Threshold
|
|
1182
|
-
local best_loc = indexOf(text, pattern, loc)
|
|
1183
|
-
if best_loc then
|
|
1184
|
-
score_threshold = min(_match_bitapScore(0, best_loc), score_threshold)
|
|
1185
|
-
end
|
|
1186
|
-
|
|
1187
|
-
local matchmask = lshift(1, #pattern - 1)
|
|
1188
|
-
best_loc = -1
|
|
1189
|
-
|
|
1190
|
-
local bin_min, bin_mid
|
|
1191
|
-
local bin_max = #pattern + #text
|
|
1192
|
-
local last_rd
|
|
1193
|
-
for d = 0, #pattern - 1, 1 do
|
|
1194
|
-
bin_min = 0
|
|
1195
|
-
bin_mid = bin_max
|
|
1196
|
-
while (bin_min < bin_mid) do
|
|
1197
|
-
if (_match_bitapScore(d, loc + bin_mid) <= score_threshold) then
|
|
1198
|
-
bin_min = bin_mid
|
|
1199
|
-
else
|
|
1200
|
-
bin_max = bin_mid
|
|
1201
|
-
end
|
|
1202
|
-
bin_mid = floor(bin_min + (bin_max - bin_min) / 2)
|
|
1203
|
-
end
|
|
1204
|
-
bin_max = bin_mid
|
|
1205
|
-
local start = max(1, loc - bin_mid + 1)
|
|
1206
|
-
local finish = min(loc + bin_mid, #text) + #pattern
|
|
1207
|
-
|
|
1208
|
-
local rd = {}
|
|
1209
|
-
for j = start, finish do
|
|
1210
|
-
rd[j] = 0
|
|
1211
|
-
end
|
|
1212
|
-
rd[finish + 1] = lshift(1, d) - 1
|
|
1213
|
-
for j = finish, start, -1 do
|
|
1214
|
-
local charMatch = s[strsub(text, j - 1, j - 1)] or 0
|
|
1215
|
-
if (d == 0) then
|
|
1216
|
-
rd[j] = band(bor((rd[j + 1] * 2), 1), charMatch)
|
|
1217
|
-
else
|
|
1218
|
-
rd[j] = bor(
|
|
1219
|
-
band(
|
|
1220
|
-
bor(
|
|
1221
|
-
lshift(rd[j + 1], 1),
|
|
1222
|
-
1
|
|
1223
|
-
),
|
|
1224
|
-
charMatch
|
|
1225
|
-
),
|
|
1226
|
-
bor(
|
|
1227
|
-
bor(
|
|
1228
|
-
lshift(bor(last_rd[j + 1], last_rd[j]), 1),
|
|
1229
|
-
1
|
|
1230
|
-
),
|
|
1231
|
-
last_rd[j + 1]
|
|
1232
|
-
)
|
|
1233
|
-
)
|
|
1234
|
-
end
|
|
1235
|
-
if (band(rd[j], matchmask) ~= 0) then
|
|
1236
|
-
local score = _match_bitapScore(d, j - 1)
|
|
1237
|
-
if (score <= score_threshold) then
|
|
1238
|
-
score_threshold = score
|
|
1239
|
-
best_loc = j - 1
|
|
1240
|
-
if (best_loc > loc) then
|
|
1241
|
-
start = max(1, loc * 2 - best_loc)
|
|
1242
|
-
else
|
|
1243
|
-
break
|
|
1244
|
-
end
|
|
1245
|
-
end
|
|
1246
|
-
end
|
|
1247
|
-
end
|
|
1248
|
-
if (_match_bitapScore(d + 1, loc) > score_threshold) then
|
|
1249
|
-
break
|
|
1250
|
-
end
|
|
1251
|
-
last_rd = rd
|
|
1252
|
-
end
|
|
1253
|
-
return best_loc
|
|
1254
|
-
end
|
|
1255
|
-
|
|
1256
|
-
local _patch_addContext,
|
|
1257
|
-
_patch_deepCopy,
|
|
1258
|
-
_patch_addPadding,
|
|
1259
|
-
_patch_splitMax,
|
|
1260
|
-
_patch_appendText,
|
|
1261
|
-
_new_patch_obj
|
|
1262
|
-
|
|
1263
|
-
function patch_make(a, opt_b, opt_c)
|
|
1264
|
-
local text1, diffs
|
|
1265
|
-
local type_a, type_b, type_c = type(a), type(opt_b), type(opt_c)
|
|
1266
|
-
if (type_a == 'string') and (type_b == 'string') and (type_c == 'nil') then
|
|
1267
|
-
text1 = a
|
|
1268
|
-
diffs = diff_main(text1, opt_b, true)
|
|
1269
|
-
if (#diffs > 2) then
|
|
1270
|
-
diff_cleanupSemantic(diffs)
|
|
1271
|
-
diff_cleanupEfficiency(diffs)
|
|
1272
|
-
end
|
|
1273
|
-
elseif (type_a == 'table') and (type_b == 'nil') and (type_c == 'nil') then
|
|
1274
|
-
diffs = a
|
|
1275
|
-
text1 = _diff_text1(diffs)
|
|
1276
|
-
elseif (type_a == 'string') and (type_b == 'table') and (type_c == 'nil') then
|
|
1277
|
-
text1 = a
|
|
1278
|
-
diffs = opt_b
|
|
1279
|
-
elseif (type_a == 'string') and (type_b == 'string') and (type_c == 'table')
|
|
1280
|
-
then
|
|
1281
|
-
text1 = a
|
|
1282
|
-
diffs = opt_c
|
|
1283
|
-
else
|
|
1284
|
-
error('Unknown call format to patch_make.')
|
|
1285
|
-
end
|
|
1286
|
-
|
|
1287
|
-
if (diffs[1] == nil) then
|
|
1288
|
-
return {}
|
|
1289
|
-
end
|
|
1290
|
-
|
|
1291
|
-
local patches = {}
|
|
1292
|
-
local patch = _new_patch_obj()
|
|
1293
|
-
local patchDiffLength = 0
|
|
1294
|
-
local char_count1 = 0
|
|
1295
|
-
local char_count2 = 0
|
|
1296
|
-
local prepatch_text, postpatch_text = text1, text1
|
|
1297
|
-
for x, diff in ipairs(diffs) do
|
|
1298
|
-
local diff_type, diff_text = diff[1], diff[2]
|
|
1299
|
-
|
|
1300
|
-
if (patchDiffLength == 0) and (diff_type ~= DIFF_EQUAL) then
|
|
1301
|
-
patch.start1 = char_count1 + 1
|
|
1302
|
-
patch.start2 = char_count2 + 1
|
|
1303
|
-
end
|
|
1304
|
-
|
|
1305
|
-
if (diff_type == DIFF_INSERT) then
|
|
1306
|
-
patchDiffLength = patchDiffLength + 1
|
|
1307
|
-
patch.diffs[patchDiffLength] = diff
|
|
1308
|
-
patch.length2 = patch.length2 + #diff_text
|
|
1309
|
-
postpatch_text = strsub(postpatch_text, 1, char_count2)
|
|
1310
|
-
.. diff_text .. strsub(postpatch_text, char_count2 + 1)
|
|
1311
|
-
elseif (diff_type == DIFF_DELETE) then
|
|
1312
|
-
patch.length1 = patch.length1 + #diff_text
|
|
1313
|
-
patchDiffLength = patchDiffLength + 1
|
|
1314
|
-
patch.diffs[patchDiffLength] = diff
|
|
1315
|
-
postpatch_text = strsub(postpatch_text, 1, char_count2)
|
|
1316
|
-
.. strsub(postpatch_text, char_count2 + #diff_text + 1)
|
|
1317
|
-
elseif (diff_type == DIFF_EQUAL) then
|
|
1318
|
-
if (#diff_text <= Patch_Margin * 2)
|
|
1319
|
-
and (patchDiffLength ~= 0) and (#diffs ~= x) then
|
|
1320
|
-
patchDiffLength = patchDiffLength + 1
|
|
1321
|
-
patch.diffs[patchDiffLength] = diff
|
|
1322
|
-
patch.length1 = patch.length1 + #diff_text
|
|
1323
|
-
patch.length2 = patch.length2 + #diff_text
|
|
1324
|
-
elseif (#diff_text >= Patch_Margin * 2) then
|
|
1325
|
-
if (patchDiffLength ~= 0) then
|
|
1326
|
-
_patch_addContext(patch, prepatch_text)
|
|
1327
|
-
patches[#patches + 1] = patch
|
|
1328
|
-
patch = _new_patch_obj()
|
|
1329
|
-
patchDiffLength = 0
|
|
1330
|
-
prepatch_text = postpatch_text
|
|
1331
|
-
char_count1 = char_count2
|
|
1332
|
-
end
|
|
1333
|
-
end
|
|
1334
|
-
end
|
|
1335
|
-
|
|
1336
|
-
if (diff_type ~= DIFF_INSERT) then
|
|
1337
|
-
char_count1 = char_count1 + #diff_text
|
|
1338
|
-
end
|
|
1339
|
-
if (diff_type ~= DIFF_DELETE) then
|
|
1340
|
-
char_count2 = char_count2 + #diff_text
|
|
1341
|
-
end
|
|
1342
|
-
end
|
|
1343
|
-
|
|
1344
|
-
if (patchDiffLength > 0) then
|
|
1345
|
-
_patch_addContext(patch, prepatch_text)
|
|
1346
|
-
patches[#patches + 1] = patch
|
|
1347
|
-
end
|
|
1348
|
-
|
|
1349
|
-
return patches
|
|
1350
|
-
end
|
|
1351
|
-
|
|
1352
|
-
function patch_apply(patches, text)
|
|
1353
|
-
if patches[1] == nil then
|
|
1354
|
-
return text, {}
|
|
1355
|
-
end
|
|
1356
|
-
|
|
1357
|
-
patches = _patch_deepCopy(patches)
|
|
1358
|
-
|
|
1359
|
-
local nullPadding = _patch_addPadding(patches)
|
|
1360
|
-
text = nullPadding .. text .. nullPadding
|
|
1361
|
-
|
|
1362
|
-
_patch_splitMax(patches)
|
|
1363
|
-
local delta = 0
|
|
1364
|
-
local results = {}
|
|
1365
|
-
for x, patch in ipairs(patches) do
|
|
1366
|
-
local expected_loc = patch.start2 + delta
|
|
1367
|
-
local text1 = _diff_text1(patch.diffs)
|
|
1368
|
-
local start_loc
|
|
1369
|
-
local end_loc = -1
|
|
1370
|
-
if #text1 > Match_MaxBits then
|
|
1371
|
-
start_loc = match_main(text,
|
|
1372
|
-
strsub(text1, 1, Match_MaxBits), expected_loc)
|
|
1373
|
-
if start_loc ~= -1 then
|
|
1374
|
-
end_loc = match_main(text, strsub(text1, -Match_MaxBits),
|
|
1375
|
-
expected_loc + #text1 - Match_MaxBits)
|
|
1376
|
-
if end_loc == -1 or start_loc >= end_loc then
|
|
1377
|
-
start_loc = -1
|
|
1378
|
-
end
|
|
1379
|
-
end
|
|
1380
|
-
else
|
|
1381
|
-
start_loc = match_main(text, text1, expected_loc)
|
|
1382
|
-
end
|
|
1383
|
-
if start_loc == -1 then
|
|
1384
|
-
results[x] = false
|
|
1385
|
-
delta = delta - patch.length2 - patch.length1
|
|
1386
|
-
else
|
|
1387
|
-
results[x] = true
|
|
1388
|
-
delta = start_loc - expected_loc
|
|
1389
|
-
local text2
|
|
1390
|
-
if end_loc == -1 then
|
|
1391
|
-
text2 = strsub(text, start_loc, start_loc + #text1 - 1)
|
|
1392
|
-
else
|
|
1393
|
-
text2 = strsub(text, start_loc, end_loc + Match_MaxBits - 1)
|
|
1394
|
-
end
|
|
1395
|
-
if text1 == text2 then
|
|
1396
|
-
text = strsub(text, 1, start_loc - 1) .. _diff_text2(patch.diffs)
|
|
1397
|
-
.. strsub(text, start_loc + #text1)
|
|
1398
|
-
else
|
|
1399
|
-
local diffs = diff_main(text1, text2, false)
|
|
1400
|
-
if (#text1 > Match_MaxBits)
|
|
1401
|
-
and (diff_levenshtein(diffs) / #text1 > Patch_DeleteThreshold) then
|
|
1402
|
-
results[x] = false
|
|
1403
|
-
else
|
|
1404
|
-
_diff_cleanupSemanticLossless(diffs)
|
|
1405
|
-
local index1 = 1
|
|
1406
|
-
local index2
|
|
1407
|
-
for y, mod in ipairs(patch.diffs) do
|
|
1408
|
-
if mod[1] ~= DIFF_EQUAL then
|
|
1409
|
-
index2 = _diff_xIndex(diffs, index1)
|
|
1410
|
-
end
|
|
1411
|
-
if mod[1] == DIFF_INSERT then
|
|
1412
|
-
text = strsub(text, 1, start_loc + index2 - 2)
|
|
1413
|
-
.. mod[2] .. strsub(text, start_loc + index2 - 1)
|
|
1414
|
-
elseif mod[1] == DIFF_DELETE then
|
|
1415
|
-
text = strsub(text, 1, start_loc + index2 - 2) .. strsub(text,
|
|
1416
|
-
start_loc + _diff_xIndex(diffs, index1 + #mod[2] - 1))
|
|
1417
|
-
end
|
|
1418
|
-
if mod[1] ~= DIFF_DELETE then
|
|
1419
|
-
index1 = index1 + #mod[2]
|
|
1420
|
-
end
|
|
1421
|
-
end
|
|
1422
|
-
end
|
|
1423
|
-
end
|
|
1424
|
-
end
|
|
1425
|
-
end
|
|
1426
|
-
text = strsub(text, #nullPadding + 1, -#nullPadding - 1)
|
|
1427
|
-
return text, results
|
|
1428
|
-
end
|
|
1429
|
-
|
|
1430
|
-
function patch_toText(patches)
|
|
1431
|
-
local text = {}
|
|
1432
|
-
for x, patch in ipairs(patches) do
|
|
1433
|
-
_patch_appendText(patch, text)
|
|
1434
|
-
end
|
|
1435
|
-
return tconcat(text)
|
|
1436
|
-
end
|
|
1437
|
-
|
|
1438
|
-
function patch_fromText(textline)
|
|
1439
|
-
local patches = {}
|
|
1440
|
-
if (#textline == 0) then
|
|
1441
|
-
return patches
|
|
1442
|
-
end
|
|
1443
|
-
local text = {}
|
|
1444
|
-
for line in gmatch(textline, '([^\n]*)') do
|
|
1445
|
-
text[#text + 1] = line
|
|
1446
|
-
end
|
|
1447
|
-
local textPointer = 1
|
|
1448
|
-
while (textPointer <= #text) do
|
|
1449
|
-
local start1, length1, start2, length2
|
|
1450
|
-
= strmatch(text[textPointer], '^@@ %-(%d+),?(%d*) %+(%d+),?(%d*) @@$')
|
|
1451
|
-
if (start1 == nil) then
|
|
1452
|
-
error('Invalid patch string: "' .. text[textPointer] .. '"')
|
|
1453
|
-
end
|
|
1454
|
-
local patch = _new_patch_obj()
|
|
1455
|
-
patches[#patches + 1] = patch
|
|
1456
|
-
|
|
1457
|
-
start1 = tonumber(start1)
|
|
1458
|
-
length1 = tonumber(length1) or 1
|
|
1459
|
-
if (length1 == 0) then
|
|
1460
|
-
start1 = start1 + 1
|
|
1461
|
-
end
|
|
1462
|
-
patch.start1 = start1
|
|
1463
|
-
patch.length1 = length1
|
|
1464
|
-
|
|
1465
|
-
start2 = tonumber(start2)
|
|
1466
|
-
length2 = tonumber(length2) or 1
|
|
1467
|
-
if (length2 == 0) then
|
|
1468
|
-
start2 = start2 + 1
|
|
1469
|
-
end
|
|
1470
|
-
patch.start2 = start2
|
|
1471
|
-
patch.length2 = length2
|
|
1472
|
-
|
|
1473
|
-
textPointer = textPointer + 1
|
|
1474
|
-
|
|
1475
|
-
while true do
|
|
1476
|
-
local line = text[textPointer]
|
|
1477
|
-
if (line == nil) then
|
|
1478
|
-
break
|
|
1479
|
-
end
|
|
1480
|
-
local sign; sign, line = strsub(line, 1, 1), strsub(line, 2)
|
|
1481
|
-
|
|
1482
|
-
local invalidDecode = false
|
|
1483
|
-
local decoded = gsub(line, '%%(.?.?)',
|
|
1484
|
-
function(c)
|
|
1485
|
-
local n = tonumber(c, 16)
|
|
1486
|
-
if (#c ~= 2) or (n == nil) then
|
|
1487
|
-
invalidDecode = true
|
|
1488
|
-
return ''
|
|
1489
|
-
end
|
|
1490
|
-
return strchar(n)
|
|
1491
|
-
end)
|
|
1492
|
-
if invalidDecode then
|
|
1493
|
-
error('Illegal escape in patch_fromText: ' .. line)
|
|
1494
|
-
end
|
|
1495
|
-
|
|
1496
|
-
line = decoded
|
|
1497
|
-
|
|
1498
|
-
if (sign == '-') then
|
|
1499
|
-
patch.diffs[#patch.diffs + 1] = {DIFF_DELETE, line}
|
|
1500
|
-
elseif (sign == '+') then
|
|
1501
|
-
patch.diffs[#patch.diffs + 1] = {DIFF_INSERT, line}
|
|
1502
|
-
elseif (sign == ' ') then
|
|
1503
|
-
patch.diffs[#patch.diffs + 1] = {DIFF_EQUAL, line}
|
|
1504
|
-
elseif (sign == '@') then
|
|
1505
|
-
break
|
|
1506
|
-
elseif (sign == '') then
|
|
1507
|
-
else
|
|
1508
|
-
error('Invalid patch mode "' .. sign .. '" in: ' .. line)
|
|
1509
|
-
end
|
|
1510
|
-
textPointer = textPointer + 1
|
|
1511
|
-
end
|
|
1512
|
-
end
|
|
1513
|
-
return patches
|
|
1514
|
-
end
|
|
1515
|
-
|
|
1516
|
-
local patch_meta = {
|
|
1517
|
-
__tostring = function(patch)
|
|
1518
|
-
local buf = {}
|
|
1519
|
-
_patch_appendText(patch, buf)
|
|
1520
|
-
return tconcat(buf)
|
|
1521
|
-
end
|
|
1522
|
-
}
|
|
1523
|
-
|
|
1524
|
-
function _new_patch_obj()
|
|
1525
|
-
return setmetatable({
|
|
1526
|
-
diffs = {};
|
|
1527
|
-
start1 = 1;
|
|
1528
|
-
start2 = 1;
|
|
1529
|
-
length1 = 0;
|
|
1530
|
-
length2 = 0;
|
|
1531
|
-
}, patch_meta)
|
|
1532
|
-
end
|
|
1533
|
-
|
|
1534
|
-
function _patch_addContext(patch, text)
|
|
1535
|
-
if (#text == 0) then
|
|
1536
|
-
return
|
|
1537
|
-
end
|
|
1538
|
-
local pattern = strsub(text, patch.start2, patch.start2 + patch.length1 - 1)
|
|
1539
|
-
local padding = 0
|
|
1540
|
-
|
|
1541
|
-
local firstMatch = indexOf(text, pattern)
|
|
1542
|
-
local secondMatch = nil
|
|
1543
|
-
if (firstMatch ~= nil) then
|
|
1544
|
-
secondMatch = indexOf(text, pattern, firstMatch + 1)
|
|
1545
|
-
end
|
|
1546
|
-
while (#pattern == 0 or secondMatch ~= nil)
|
|
1547
|
-
and (#pattern < Match_MaxBits - Patch_Margin - Patch_Margin) do
|
|
1548
|
-
padding = padding + Patch_Margin
|
|
1549
|
-
pattern = strsub(text, max(1, patch.start2 - padding),
|
|
1550
|
-
patch.start2 + patch.length1 - 1 + padding)
|
|
1551
|
-
firstMatch = indexOf(text, pattern)
|
|
1552
|
-
if (firstMatch ~= nil) then
|
|
1553
|
-
secondMatch = indexOf(text, pattern, firstMatch + 1)
|
|
1554
|
-
else
|
|
1555
|
-
secondMatch = nil
|
|
1556
|
-
end
|
|
1557
|
-
end
|
|
1558
|
-
padding = padding + Patch_Margin
|
|
1559
|
-
|
|
1560
|
-
local prefix = strsub(text, max(1, patch.start2 - padding), patch.start2 - 1)
|
|
1561
|
-
if (#prefix > 0) then
|
|
1562
|
-
tinsert(patch.diffs, 1, {DIFF_EQUAL, prefix})
|
|
1563
|
-
end
|
|
1564
|
-
|
|
1565
|
-
local suffix = strsub(text, patch.start2 + patch.length1,
|
|
1566
|
-
patch.start2 + patch.length1 - 1 + padding)
|
|
1567
|
-
if (#suffix > 0) then
|
|
1568
|
-
patch.diffs[#patch.diffs + 1] = {DIFF_EQUAL, suffix}
|
|
1569
|
-
end
|
|
1570
|
-
|
|
1571
|
-
patch.start1 = patch.start1 - #prefix
|
|
1572
|
-
patch.start2 = patch.start2 - #prefix
|
|
1573
|
-
patch.length1 = patch.length1 + #prefix + #suffix
|
|
1574
|
-
patch.length2 = patch.length2 + #prefix + #suffix
|
|
1575
|
-
end
|
|
1576
|
-
|
|
1577
|
-
function _patch_deepCopy(patches)
|
|
1578
|
-
local patchesCopy = {}
|
|
1579
|
-
for x, patch in ipairs(patches) do
|
|
1580
|
-
local patchCopy = _new_patch_obj()
|
|
1581
|
-
local diffsCopy = {}
|
|
1582
|
-
for i, diff in ipairs(patch.diffs) do
|
|
1583
|
-
diffsCopy[i] = {diff[1], diff[2]}
|
|
1584
|
-
end
|
|
1585
|
-
patchCopy.diffs = diffsCopy
|
|
1586
|
-
patchCopy.start1 = patch.start1
|
|
1587
|
-
patchCopy.start2 = patch.start2
|
|
1588
|
-
patchCopy.length1 = patch.length1
|
|
1589
|
-
patchCopy.length2 = patch.length2
|
|
1590
|
-
patchesCopy[x] = patchCopy
|
|
1591
|
-
end
|
|
1592
|
-
return patchesCopy
|
|
1593
|
-
end
|
|
1594
|
-
|
|
1595
|
-
function _patch_addPadding(patches)
|
|
1596
|
-
local paddingLength = Patch_Margin
|
|
1597
|
-
local nullPadding = ''
|
|
1598
|
-
for x = 1, paddingLength do
|
|
1599
|
-
nullPadding = nullPadding .. strchar(x)
|
|
1600
|
-
end
|
|
1601
|
-
|
|
1602
|
-
for x, patch in ipairs(patches) do
|
|
1603
|
-
patch.start1 = patch.start1 + paddingLength
|
|
1604
|
-
patch.start2 = patch.start2 + paddingLength
|
|
1605
|
-
end
|
|
1606
|
-
|
|
1607
|
-
local patch = patches[1]
|
|
1608
|
-
local diffs = patch.diffs
|
|
1609
|
-
local firstDiff = diffs[1]
|
|
1610
|
-
if (firstDiff == nil) or (firstDiff[1] ~= DIFF_EQUAL) then
|
|
1611
|
-
tinsert(diffs, 1, {DIFF_EQUAL, nullPadding})
|
|
1612
|
-
patch.start1 = patch.start1 - paddingLength
|
|
1613
|
-
patch.start2 = patch.start2 - paddingLength
|
|
1614
|
-
patch.length1 = patch.length1 + paddingLength
|
|
1615
|
-
patch.length2 = patch.length2 + paddingLength
|
|
1616
|
-
elseif (paddingLength > #firstDiff[2]) then
|
|
1617
|
-
local extraLength = paddingLength - #firstDiff[2]
|
|
1618
|
-
firstDiff[2] = strsub(nullPadding, #firstDiff[2] + 1) .. firstDiff[2]
|
|
1619
|
-
patch.start1 = patch.start1 - extraLength
|
|
1620
|
-
patch.start2 = patch.start2 - extraLength
|
|
1621
|
-
patch.length1 = patch.length1 + extraLength
|
|
1622
|
-
patch.length2 = patch.length2 + extraLength
|
|
1623
|
-
end
|
|
1624
|
-
|
|
1625
|
-
patch = patches[#patches]
|
|
1626
|
-
diffs = patch.diffs
|
|
1627
|
-
local lastDiff = diffs[#diffs]
|
|
1628
|
-
if (lastDiff == nil) or (lastDiff[1] ~= DIFF_EQUAL) then
|
|
1629
|
-
diffs[#diffs + 1] = {DIFF_EQUAL, nullPadding}
|
|
1630
|
-
patch.length1 = patch.length1 + paddingLength
|
|
1631
|
-
patch.length2 = patch.length2 + paddingLength
|
|
1632
|
-
elseif (paddingLength > #lastDiff[2]) then
|
|
1633
|
-
local extraLength = paddingLength - #lastDiff[2]
|
|
1634
|
-
lastDiff[2] = lastDiff[2] .. strsub(nullPadding, 1, extraLength)
|
|
1635
|
-
patch.length1 = patch.length1 + extraLength
|
|
1636
|
-
patch.length2 = patch.length2 + extraLength
|
|
1637
|
-
end
|
|
1638
|
-
|
|
1639
|
-
return nullPadding
|
|
1640
|
-
end
|
|
1641
|
-
|
|
1642
|
-
function _patch_splitMax(patches)
|
|
1643
|
-
local patch_size = Match_MaxBits
|
|
1644
|
-
local x = 1
|
|
1645
|
-
while true do
|
|
1646
|
-
local patch = patches[x]
|
|
1647
|
-
if patch == nil then
|
|
1648
|
-
return
|
|
1649
|
-
end
|
|
1650
|
-
if patch.length1 > patch_size then
|
|
1651
|
-
local bigpatch = patch
|
|
1652
|
-
tremove(patches, x)
|
|
1653
|
-
x = x - 1
|
|
1654
|
-
local start1 = bigpatch.start1
|
|
1655
|
-
local start2 = bigpatch.start2
|
|
1656
|
-
local precontext = ''
|
|
1657
|
-
while bigpatch.diffs[1] do
|
|
1658
|
-
local patch = _new_patch_obj()
|
|
1659
|
-
local empty = true
|
|
1660
|
-
patch.start1 = start1 - #precontext
|
|
1661
|
-
patch.start2 = start2 - #precontext
|
|
1662
|
-
if precontext ~= '' then
|
|
1663
|
-
patch.length1, patch.length2 = #precontext, #precontext
|
|
1664
|
-
patch.diffs[#patch.diffs + 1] = {DIFF_EQUAL, precontext}
|
|
1665
|
-
end
|
|
1666
|
-
while bigpatch.diffs[1] and (patch.length1 < patch_size-Patch_Margin) do
|
|
1667
|
-
local diff_type = bigpatch.diffs[1][1]
|
|
1668
|
-
local diff_text = bigpatch.diffs[1][2]
|
|
1669
|
-
if (diff_type == DIFF_INSERT) then
|
|
1670
|
-
patch.length2 = patch.length2 + #diff_text
|
|
1671
|
-
start2 = start2 + #diff_text
|
|
1672
|
-
patch.diffs[#(patch.diffs) + 1] = bigpatch.diffs[1]
|
|
1673
|
-
tremove(bigpatch.diffs, 1)
|
|
1674
|
-
empty = false
|
|
1675
|
-
elseif (diff_type == DIFF_DELETE) and (#patch.diffs == 1)
|
|
1676
|
-
and (patch.diffs[1][1] == DIFF_EQUAL)
|
|
1677
|
-
and (#diff_text > 2 * patch_size) then
|
|
1678
|
-
patch.length1 = patch.length1 + #diff_text
|
|
1679
|
-
start1 = start1 + #diff_text
|
|
1680
|
-
empty = false
|
|
1681
|
-
patch.diffs[#patch.diffs + 1] = {diff_type, diff_text}
|
|
1682
|
-
tremove(bigpatch.diffs, 1)
|
|
1683
|
-
else
|
|
1684
|
-
diff_text = strsub(diff_text, 1,
|
|
1685
|
-
patch_size - patch.length1 - Patch_Margin)
|
|
1686
|
-
patch.length1 = patch.length1 + #diff_text
|
|
1687
|
-
start1 = start1 + #diff_text
|
|
1688
|
-
if (diff_type == DIFF_EQUAL) then
|
|
1689
|
-
patch.length2 = patch.length2 + #diff_text
|
|
1690
|
-
start2 = start2 + #diff_text
|
|
1691
|
-
else
|
|
1692
|
-
empty = false
|
|
1693
|
-
end
|
|
1694
|
-
patch.diffs[#patch.diffs + 1] = {diff_type, diff_text}
|
|
1695
|
-
if (diff_text == bigpatch.diffs[1][2]) then
|
|
1696
|
-
tremove(bigpatch.diffs, 1)
|
|
1697
|
-
else
|
|
1698
|
-
bigpatch.diffs[1][2]
|
|
1699
|
-
= strsub(bigpatch.diffs[1][2], #diff_text + 1)
|
|
1700
|
-
end
|
|
1701
|
-
end
|
|
1702
|
-
end
|
|
1703
|
-
precontext = _diff_text2(patch.diffs)
|
|
1704
|
-
precontext = strsub(precontext, -Patch_Margin)
|
|
1705
|
-
local postcontext = strsub(_diff_text1(bigpatch.diffs), 1, Patch_Margin)
|
|
1706
|
-
if postcontext ~= '' then
|
|
1707
|
-
patch.length1 = patch.length1 + #postcontext
|
|
1708
|
-
patch.length2 = patch.length2 + #postcontext
|
|
1709
|
-
if patch.diffs[1]
|
|
1710
|
-
and (patch.diffs[#patch.diffs][1] == DIFF_EQUAL) then
|
|
1711
|
-
patch.diffs[#patch.diffs][2] = patch.diffs[#patch.diffs][2]
|
|
1712
|
-
.. postcontext
|
|
1713
|
-
else
|
|
1714
|
-
patch.diffs[#patch.diffs + 1] = {DIFF_EQUAL, postcontext}
|
|
1715
|
-
end
|
|
1716
|
-
end
|
|
1717
|
-
if not empty then
|
|
1718
|
-
x = x + 1
|
|
1719
|
-
tinsert(patches, x, patch)
|
|
1720
|
-
end
|
|
1721
|
-
end
|
|
1722
|
-
end
|
|
1723
|
-
x = x + 1
|
|
1724
|
-
end
|
|
1725
|
-
end
|
|
1726
|
-
|
|
1727
|
-
function _patch_appendText(patch, text)
|
|
1728
|
-
local coords1, coords2
|
|
1729
|
-
local length1, length2 = patch.length1, patch.length2
|
|
1730
|
-
local start1, start2 = patch.start1, patch.start2
|
|
1731
|
-
local diffs = patch.diffs
|
|
1732
|
-
|
|
1733
|
-
if length1 == 1 then
|
|
1734
|
-
coords1 = start1
|
|
1735
|
-
else
|
|
1736
|
-
coords1 = ((length1 == 0) and (start1 - 1) or start1) .. ',' .. length1
|
|
1737
|
-
end
|
|
1738
|
-
|
|
1739
|
-
if length2 == 1 then
|
|
1740
|
-
coords2 = start2
|
|
1741
|
-
else
|
|
1742
|
-
coords2 = ((length2 == 0) and (start2 - 1) or start2) .. ',' .. length2
|
|
1743
|
-
end
|
|
1744
|
-
text[#text + 1] = '@@ -' .. coords1 .. ' +' .. coords2 .. ' @@\n'
|
|
1745
|
-
|
|
1746
|
-
local op
|
|
1747
|
-
for x, diff in ipairs(patch.diffs) do
|
|
1748
|
-
local diff_type = diff[1]
|
|
1749
|
-
if diff_type == DIFF_INSERT then
|
|
1750
|
-
op = '+'
|
|
1751
|
-
elseif diff_type == DIFF_DELETE then
|
|
1752
|
-
op = '-'
|
|
1753
|
-
elseif diff_type == DIFF_EQUAL then
|
|
1754
|
-
op = ' '
|
|
1755
|
-
end
|
|
1756
|
-
text[#text + 1] = op
|
|
1757
|
-
.. gsub(diffs[x][2], percentEncode_pattern, percentEncode_replace)
|
|
1758
|
-
.. '\n'
|
|
1759
|
-
end
|
|
1760
|
-
|
|
1761
|
-
return text
|
|
1762
|
-
end
|
|
1763
|
-
|
|
1764
|
-
local _M = {}
|
|
1765
|
-
|
|
1766
|
-
_M.DIFF_DELETE = DIFF_DELETE
|
|
1767
|
-
_M.DIFF_INSERT = DIFF_INSERT
|
|
1768
|
-
_M.DIFF_EQUAL = DIFF_EQUAL
|
|
1769
|
-
|
|
1770
|
-
_M.diff_main = diff_main
|
|
1771
|
-
_M.diff_cleanupSemantic = diff_cleanupSemantic
|
|
1772
|
-
_M.diff_cleanupEfficiency = diff_cleanupEfficiency
|
|
1773
|
-
_M.diff_levenshtein = diff_levenshtein
|
|
1774
|
-
_M.diff_prettyHtml = diff_prettyHtml
|
|
1775
|
-
|
|
1776
|
-
_M.match_main = match_main
|
|
1777
|
-
|
|
1778
|
-
_M.patch_make = patch_make
|
|
1779
|
-
_M.patch_toText = patch_toText
|
|
1780
|
-
_M.patch_fromText = patch_fromText
|
|
1781
|
-
_M.patch_apply = patch_apply
|
|
1782
|
-
|
|
1783
|
-
_M.diff_commonPrefix = _diff_commonPrefix
|
|
1784
|
-
_M.diff_commonSuffix = _diff_commonSuffix
|
|
1785
|
-
_M.diff_commonOverlap = _diff_commonOverlap
|
|
1786
|
-
_M.diff_halfMatch = _diff_halfMatch
|
|
1787
|
-
_M.diff_bisect = _diff_bisect
|
|
1788
|
-
_M.diff_cleanupMerge = _diff_cleanupMerge
|
|
1789
|
-
_M.diff_cleanupSemanticLossless = _diff_cleanupSemanticLossless
|
|
1790
|
-
_M.diff_text1 = _diff_text1
|
|
1791
|
-
_M.diff_text2 = _diff_text2
|
|
1792
|
-
_M.diff_toDelta = _diff_toDelta
|
|
1793
|
-
_M.diff_fromDelta = _diff_fromDelta
|
|
1794
|
-
_M.diff_xIndex = _diff_xIndex
|
|
1795
|
-
_M.match_alphabet = _match_alphabet
|
|
1796
|
-
_M.match_bitap = _match_bitap
|
|
1797
|
-
_M.new_patch_obj = _new_patch_obj
|
|
1798
|
-
_M.patch_addContext = _patch_addContext
|
|
1799
|
-
_M.patch_splitMax = _patch_splitMax
|
|
1800
|
-
_M.patch_addPadding = _patch_addPadding
|
|
1801
|
-
_M.settings = settings
|
|
1802
|
-
|
|
1803
|
-
dmp = _M
|
|
1804
|
-
|
|
1805
|
-
local bint = require('.bint')(256)
|
|
1806
|
-
local json = require('json')
|
|
1807
|
-
local base64 = require(".base64")
|
|
1808
|
-
local ao = require("ao")
|
|
1809
|
-
|
|
1810
|
-
Transferable = true
|
|
1811
|
-
|
|
1812
|
-
local function checkValidAddress(address)
|
|
1813
|
-
if not address or type(address) ~= 'string' then
|
|
1814
|
-
return false
|
|
1815
|
-
end
|
|
1816
|
-
|
|
1817
|
-
return string.match(address, "^[%w%-_]+$") ~= nil and #address == 43
|
|
1818
|
-
end
|
|
1819
|
-
|
|
1820
|
-
local function checkValidAmount(data)
|
|
1821
|
-
return (math.type(tonumber(data)) == 'integer' or math.type(tonumber(data)) == 'float') and bint(data) > 0
|
|
1822
|
-
end
|
|
1823
|
-
|
|
1824
|
-
local function decodeMessageData(data)
|
|
1825
|
-
local status, decodedData = pcall(json.decode, data)
|
|
1826
|
-
|
|
1827
|
-
if not status or type(decodedData) ~= 'table' then
|
|
1828
|
-
return false, nil
|
|
1829
|
-
end
|
|
1830
|
-
|
|
1831
|
-
return true, decodedData
|
|
1832
|
-
end
|
|
1833
|
-
|
|
1834
|
-
-- Read process state
|
|
1835
|
-
Handlers.add('Info', Handlers.utils.hasMatchingTag('Action', 'Info'), function(msg)
|
|
1836
|
-
ao.send({
|
|
1837
|
-
Target = msg.From,
|
|
1838
|
-
Action = 'Read-Success',
|
|
1839
|
-
Data = json.encode({
|
|
1840
|
-
Name = Name,
|
|
1841
|
-
Description = Description,
|
|
1842
|
-
Ticker = Ticker,
|
|
1843
|
-
Denomination = Denomination,
|
|
1844
|
-
Balances = Balances,
|
|
1845
|
-
Transferable = Transferable,
|
|
1846
|
-
Thumbnail = Thumbnail,
|
|
1847
|
-
Collections = Collections
|
|
1848
|
-
})
|
|
1849
|
-
})
|
|
1850
|
-
end)
|
|
1851
|
-
|
|
1852
|
-
-- Transfer balance to recipient (Data - { Recipient, Quantity })
|
|
1853
|
-
Handlers.add('Transfer', Handlers.utils.hasMatchingTag('Action', 'Transfer'), function(msg)
|
|
1854
|
-
if not Transferable then
|
|
1855
|
-
ao.send({ Target = msg.From, Action = 'Validation-Error', Tags = { Status = 'Error', Message = 'Transfers are not allowed' } })
|
|
1856
|
-
return
|
|
1857
|
-
end
|
|
1858
|
-
|
|
1859
|
-
local data = {
|
|
1860
|
-
Recipient = msg.Tags.Recipient,
|
|
1861
|
-
Quantity = msg.Tags.Quantity
|
|
1862
|
-
}
|
|
1863
|
-
|
|
1864
|
-
if checkValidAddress(data.Recipient) and checkValidAmount(data.Quantity) then
|
|
1865
|
-
-- Transfer is valid, calculate balances
|
|
1866
|
-
if not Balances[data.Recipient] then
|
|
1867
|
-
Balances[data.Recipient] = '0'
|
|
1868
|
-
end
|
|
1869
|
-
|
|
1870
|
-
Balances[msg.From] = tostring(bint(Balances[msg.From]) - bint(data.Quantity))
|
|
1871
|
-
Balances[data.Recipient] = tostring(bint(Balances[data.Recipient]) + bint(data.Quantity))
|
|
1872
|
-
|
|
1873
|
-
-- If new balance zeroes out then remove it from the table
|
|
1874
|
-
if bint(Balances[msg.From]) <= 0 then
|
|
1875
|
-
Balances[msg.From] = nil
|
|
1876
|
-
end
|
|
1877
|
-
if bint(Balances[data.Recipient]) <= 0 then
|
|
1878
|
-
Balances[data.Recipient] = nil
|
|
1879
|
-
end
|
|
1880
|
-
|
|
1881
|
-
local debitNoticeTags = {
|
|
1882
|
-
Status = 'Success',
|
|
1883
|
-
Message = 'Balance transferred, debit notice issued',
|
|
1884
|
-
Recipient = msg.Tags.Recipient,
|
|
1885
|
-
Quantity = msg.Tags.Quantity,
|
|
1886
|
-
}
|
|
1887
|
-
|
|
1888
|
-
local creditNoticeTags = {
|
|
1889
|
-
Status = 'Success',
|
|
1890
|
-
Message = 'Balance transferred, credit notice issued',
|
|
1891
|
-
Sender = msg.From,
|
|
1892
|
-
Quantity = msg.Tags.Quantity,
|
|
1893
|
-
}
|
|
1894
|
-
|
|
1895
|
-
for tagName, tagValue in pairs(msg) do
|
|
1896
|
-
if string.sub(tagName, 1, 2) == 'X-' then
|
|
1897
|
-
debitNoticeTags[tagName] = tagValue
|
|
1898
|
-
creditNoticeTags[tagName] = tagValue
|
|
1899
|
-
end
|
|
1900
|
-
end
|
|
1901
|
-
|
|
1902
|
-
-- Send a debit notice to the sender
|
|
1903
|
-
ao.send({
|
|
1904
|
-
Target = msg.From,
|
|
1905
|
-
Action = 'Debit-Notice',
|
|
1906
|
-
Tags = debitNoticeTags,
|
|
1907
|
-
Data = json.encode({
|
|
1908
|
-
Recipient = data.Recipient,
|
|
1909
|
-
Quantity = tostring(data.Quantity)
|
|
1910
|
-
})
|
|
1911
|
-
})
|
|
1912
|
-
|
|
1913
|
-
-- Send a credit notice to the recipient
|
|
1914
|
-
ao.send({
|
|
1915
|
-
Target = data.Recipient,
|
|
1916
|
-
Action = 'Credit-Notice',
|
|
1917
|
-
Tags = creditNoticeTags,
|
|
1918
|
-
Data = json.encode({
|
|
1919
|
-
Sender = msg.From,
|
|
1920
|
-
Quantity = tostring(data.Quantity)
|
|
1921
|
-
})
|
|
1922
|
-
})
|
|
1923
|
-
end
|
|
1924
|
-
end)
|
|
1925
|
-
|
|
1926
|
-
-- Mint new tokens (Data - { Quantity })
|
|
1927
|
-
Handlers.add('Mint', Handlers.utils.hasMatchingTag('Action', 'Mint'), function(msg)
|
|
1928
|
-
local decodeCheck, data = decodeMessageData(msg.Data)
|
|
1929
|
-
|
|
1930
|
-
if decodeCheck and data then
|
|
1931
|
-
-- Check if quantity is present
|
|
1932
|
-
if not data.Quantity then
|
|
1933
|
-
ao.send({ Target = msg.From, Action = 'Input-Error', Tags = { Status = 'Error', Message = 'Invalid arguments, required { Quantity }' } })
|
|
1934
|
-
return
|
|
1935
|
-
end
|
|
1936
|
-
|
|
1937
|
-
-- Check if quantity is a valid integer greater than zero
|
|
1938
|
-
if not checkValidAmount(data.Quantity) then
|
|
1939
|
-
ao.send({ Target = msg.From, Action = 'Validation-Error', Tags = { Status = 'Error', Message = 'Quantity must be an integer greater than zero' } })
|
|
1940
|
-
return
|
|
1941
|
-
end
|
|
1942
|
-
|
|
1943
|
-
-- Check if owner is sender
|
|
1944
|
-
if msg.From ~= Owner then
|
|
1945
|
-
ao.send({ Target = msg.From, Action = 'Validation-Error', Tags = { Status = 'Error', Message = 'Only the process owner can mint new tokens' } })
|
|
1946
|
-
return
|
|
1947
|
-
end
|
|
1948
|
-
|
|
1949
|
-
-- Mint request is valid, add tokens to the pool
|
|
1950
|
-
if not Balances[Owner] then
|
|
1951
|
-
Balances[Owner] = '0'
|
|
1952
|
-
end
|
|
1953
|
-
|
|
1954
|
-
Balances[Owner] = tostring(bint(Balances[Owner]) + bint(data.Quantity))
|
|
1955
|
-
|
|
1956
|
-
ao.send({ Target = msg.From, Action = 'Mint-Success', Tags = { Status = 'Success', Message = 'Tokens minted' } })
|
|
1957
|
-
else
|
|
1958
|
-
ao.send({
|
|
1959
|
-
Target = msg.From,
|
|
1960
|
-
Action = 'Input-Error',
|
|
1961
|
-
Tags = {
|
|
1962
|
-
Status = 'Error',
|
|
1963
|
-
Message = string.format('Failed to parse data, received: %s. %s', msg.Data,
|
|
1964
|
-
'Data must be an object - { Quantity }')
|
|
1965
|
-
}
|
|
1966
|
-
})
|
|
1967
|
-
end
|
|
1968
|
-
end)
|
|
1969
|
-
|
|
1970
|
-
-- Read balance (Data - { Target })
|
|
1971
|
-
Handlers.add('Balance', Handlers.utils.hasMatchingTag('Action', 'Balance'), function(msg)
|
|
1972
|
-
local decodeCheck, data = decodeMessageData(msg.Data)
|
|
1973
|
-
|
|
1974
|
-
if decodeCheck and data then
|
|
1975
|
-
-- Check if target is present
|
|
1976
|
-
if not data.Target then
|
|
1977
|
-
ao.send({ Target = msg.From, Action = 'Input-Error', Tags = { Status = 'Error', Message = 'Invalid arguments, required { Target }' } })
|
|
1978
|
-
return
|
|
1979
|
-
end
|
|
1980
|
-
|
|
1981
|
-
-- Check if target is a valid address
|
|
1982
|
-
if not checkValidAddress(data.Target) then
|
|
1983
|
-
ao.send({ Target = msg.From, Action = 'Validation-Error', Tags = { Status = 'Error', Message = 'Target is not a valid address' } })
|
|
1984
|
-
return
|
|
1985
|
-
end
|
|
1986
|
-
|
|
1987
|
-
-- Check if target has a balance
|
|
1988
|
-
if not Balances[data.Target] then
|
|
1989
|
-
ao.send({ Target = msg.From, Action = 'Read-Error', Tags = { Status = 'Error', Message = 'Target does not have a balance' } })
|
|
1990
|
-
return
|
|
1991
|
-
end
|
|
1992
|
-
|
|
1993
|
-
ao.send({
|
|
1994
|
-
Target = msg.From,
|
|
1995
|
-
Action = 'Read-Success',
|
|
1996
|
-
Tags = { Status = 'Success', Message = 'Balance received' },
|
|
1997
|
-
Data =
|
|
1998
|
-
Balances[data.Target]
|
|
1999
|
-
})
|
|
2000
|
-
else
|
|
2001
|
-
ao.send({
|
|
2002
|
-
Target = msg.From,
|
|
2003
|
-
Action = 'Input-Error',
|
|
2004
|
-
Tags = {
|
|
2005
|
-
Status = 'Error',
|
|
2006
|
-
Message = string.format('Failed to parse data, received: %s. %s', msg.Data,
|
|
2007
|
-
'Data must be an object - { Target }')
|
|
2008
|
-
}
|
|
2009
|
-
})
|
|
2010
|
-
end
|
|
2011
|
-
end)
|
|
2012
|
-
|
|
2013
|
-
-- Read balances
|
|
2014
|
-
Handlers.add('Balances', Handlers.utils.hasMatchingTag('Action', 'Balances'),
|
|
2015
|
-
function(msg) ao.send({ Target = msg.From, Action = 'Read-Success', Data = json.encode(Balances) }) end)
|
|
2016
|
-
|
|
2017
|
-
-- Initialize a request to add the uploaded asset to a profile
|
|
2018
|
-
Handlers.add('Add-Asset-To-Profile', Handlers.utils.hasMatchingTag('Action', 'Add-Asset-To-Profile'), function(msg)
|
|
2019
|
-
if checkValidAddress(msg.Tags.ProfileProcess) then
|
|
2020
|
-
-- ao.assign({ Processes = { msg.Tags.ProfileProcess }, Message = ao.id })
|
|
2021
|
-
ao.send({
|
|
2022
|
-
Target = msg.Tags.ProfileProcess,
|
|
2023
|
-
Action = 'Add-Uploaded-Asset',
|
|
2024
|
-
Data = json.encode({
|
|
2025
|
-
Id = ao.id,
|
|
2026
|
-
Quantity = msg.Tags.Quantity or '0'
|
|
2027
|
-
})
|
|
2028
|
-
})
|
|
2029
|
-
else
|
|
2030
|
-
ao.send({
|
|
2031
|
-
Target = msg.From,
|
|
2032
|
-
Action = 'Input-Error',
|
|
2033
|
-
Tags = {
|
|
2034
|
-
Status = 'Error',
|
|
2035
|
-
Message = 'ProfileProcess tag not specified or not a valid Process ID'
|
|
2036
|
-
}
|
|
2037
|
-
})
|
|
2038
|
-
end
|
|
2039
|
-
end)
|
|
2040
|
-
|
|
2041
|
-
Handlers.add('Add-To-Collection-Success', Handlers.utils.hasMatchingTag('Action', 'Add-To-Collection-Success'), function(msg)
|
|
2042
|
-
local exists = false
|
|
2043
|
-
for i, id in ipairs(Collections) do
|
|
2044
|
-
if id == msg.From then
|
|
2045
|
-
exists = true
|
|
2046
|
-
break
|
|
2047
|
-
end
|
|
2048
|
-
end
|
|
2049
|
-
|
|
2050
|
-
if not exists then
|
|
2051
|
-
table.insert(Collections, msg.From)
|
|
2052
|
-
end
|
|
2053
|
-
end)
|
|
2054
|
-
|
|
2055
|
-
Handlers.add('Remove-From-Collection-Success', Handlers.utils.hasMatchingTag('Action', 'Remove-From-Collection-Success'), function(msg)
|
|
2056
|
-
for i, id in ipairs(Collections) do
|
|
2057
|
-
if id == msg.From then
|
|
2058
|
-
table.remove(Collections, i)
|
|
2059
|
-
break
|
|
2060
|
-
end
|
|
2061
|
-
end
|
|
2062
|
-
end)
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
if not data then
|
|
2066
|
-
data = nil
|
|
2067
|
-
end
|
|
2068
|
-
|
|
2069
|
-
if not version then
|
|
2070
|
-
version = "0.0.1"
|
|
2071
|
-
end
|
|
2072
|
-
|
|
2073
|
-
if not versions then
|
|
2074
|
-
versions = {}
|
|
2075
|
-
end
|
|
2076
|
-
|
|
2077
|
-
if not editors then
|
|
2078
|
-
editors = { ao.env.Process.Owner }
|
|
2079
|
-
end
|
|
2080
|
-
|
|
2081
|
-
local function reverse_patch(patch)
|
|
2082
|
-
local reversed_patch = {}
|
|
2083
|
-
for _, p in ipairs(patch) do
|
|
2084
|
-
local diffs = p.diffs
|
|
2085
|
-
local reversed_diffs = {}
|
|
2086
|
-
for _, diff in ipairs(diffs) do
|
|
2087
|
-
local op, text = diff[1], diff[2]
|
|
2088
|
-
table.insert(reversed_diffs, { -op, text })
|
|
2089
|
-
end
|
|
2090
|
-
table.insert(reversed_patch, {
|
|
2091
|
-
diffs = reversed_diffs,
|
|
2092
|
-
start1 = p.start2,
|
|
2093
|
-
start2 = p.start1,
|
|
2094
|
-
length1 = p.length2,
|
|
2095
|
-
length2 = p.length1
|
|
2096
|
-
})
|
|
2097
|
-
end
|
|
2098
|
-
return reversed_patch
|
|
2099
|
-
end
|
|
2100
|
-
|
|
2101
|
-
local function is_editor(from)
|
|
2102
|
-
for _, editor in ipairs(editors) do
|
|
2103
|
-
if from == editor then
|
|
2104
|
-
return true
|
|
2105
|
-
end
|
|
2106
|
-
end
|
|
2107
|
-
return false
|
|
2108
|
-
end
|
|
2109
|
-
|
|
2110
|
-
local function checkValidAddress(address)
|
|
2111
|
-
if not address or type(address) ~= 'string' then
|
|
2112
|
-
return false
|
|
2113
|
-
end
|
|
2114
|
-
|
|
2115
|
-
return string.match(address, "^[%w%-_]+$") ~= nil and #address == 43
|
|
2116
|
-
end
|
|
2117
|
-
|
|
2118
|
-
Handlers.add(
|
|
2119
|
-
"get",
|
|
2120
|
-
Handlers.utils.hasMatchingTag("Action", "Get"),
|
|
2121
|
-
function (msg)
|
|
2122
|
-
if msg.Tags.Version then
|
|
2123
|
-
local __patches = nil
|
|
2124
|
-
for j = #versions, 1, -1 do
|
|
2125
|
-
local v = versions[j]
|
|
2126
|
-
local _data = data
|
|
2127
|
-
if __patches then
|
|
2128
|
-
local _patches = dmp.patch_fromText(base64.decode(__patches))
|
|
2129
|
-
local reversed = reverse_patch(_patches)
|
|
2130
|
-
_data = dmp.patch_apply(reversed, _data)
|
|
2131
|
-
end
|
|
2132
|
-
__patches = v.patches
|
|
2133
|
-
if v.version == msg.Tags.Version then
|
|
2134
|
-
ao.send({
|
|
2135
|
-
Target = msg.From,
|
|
2136
|
-
Tags = {
|
|
2137
|
-
Data = _data,
|
|
2138
|
-
Version = v.version,
|
|
2139
|
-
Date = tostring(v.date)
|
|
2140
|
-
}
|
|
2141
|
-
})
|
|
2142
|
-
end
|
|
2143
|
-
end
|
|
2144
|
-
else
|
|
2145
|
-
ao.send({
|
|
2146
|
-
Target = msg.From,
|
|
2147
|
-
Tags = {
|
|
2148
|
-
Data = data,
|
|
2149
|
-
Version = version
|
|
2150
|
-
}
|
|
2151
|
-
})
|
|
2152
|
-
end
|
|
2153
|
-
end
|
|
2154
|
-
)
|
|
2155
|
-
|
|
2156
|
-
Handlers.add(
|
|
2157
|
-
"list",
|
|
2158
|
-
Handlers.utils.hasMatchingTag("Action", "List"),
|
|
2159
|
-
function (msg)
|
|
2160
|
-
ao.send({Target = msg.From, Tags = {
|
|
2161
|
-
Versions = json.encode(versions)
|
|
2162
|
-
|
|
2163
|
-
}})
|
|
2164
|
-
end
|
|
2165
|
-
)
|
|
2166
|
-
|
|
2167
|
-
Handlers.add(
|
|
2168
|
-
"editors",
|
|
2169
|
-
Handlers.utils.hasMatchingTag("Action", "Editors"),
|
|
2170
|
-
function (msg)
|
|
2171
|
-
ao.send({Target = msg.From, Tags = {
|
|
2172
|
-
Editors = json.encode(editors)
|
|
2173
|
-
|
|
2174
|
-
}})
|
|
2175
|
-
end
|
|
2176
|
-
)
|
|
2177
|
-
|
|
2178
|
-
Handlers.add(
|
|
2179
|
-
"add-editor",
|
|
2180
|
-
Handlers.utils.hasMatchingTag("Action", "Add-Editor"),
|
|
2181
|
-
function (msg)
|
|
2182
|
-
assert(type(msg.Tags.Editor) == "string" and checkValidAddress(msg.Tags.Editor), 'A valid editor is required!')
|
|
2183
|
-
local exists = false
|
|
2184
|
-
for _, editor in ipairs(editors) do
|
|
2185
|
-
if msg.Tags.Editor == editor then
|
|
2186
|
-
exists = true
|
|
2187
|
-
break
|
|
2188
|
-
end
|
|
2189
|
-
end
|
|
2190
|
-
assert(exists == false, 'Editor already exists!')
|
|
2191
|
-
table.insert(editors,msg.Tags.Editor)
|
|
2192
|
-
ao.send({
|
|
2193
|
-
Target = msg.From,
|
|
2194
|
-
Data = "editor added!",
|
|
2195
|
-
Tags = {
|
|
2196
|
-
Editors = json.encode(editors)
|
|
2197
|
-
|
|
2198
|
-
}
|
|
2199
|
-
})
|
|
2200
|
-
end
|
|
2201
|
-
)
|
|
2202
|
-
|
|
2203
|
-
Handlers.add(
|
|
2204
|
-
"remove-editor",
|
|
2205
|
-
Handlers.utils.hasMatchingTag("Action", "Remove-Editor"),
|
|
2206
|
-
function (msg)
|
|
2207
|
-
assert(type(msg.Tags.Editor) == "string" and checkValidAddress(msg.Tags.Editor), 'A valid editor is required!')
|
|
2208
|
-
local exists = false
|
|
2209
|
-
for i, editor in ipairs(editors) do
|
|
2210
|
-
if msg.Tags.Editor == editor then
|
|
2211
|
-
exists = true
|
|
2212
|
-
table.remove(editors, i)
|
|
2213
|
-
break
|
|
2214
|
-
end
|
|
2215
|
-
end
|
|
2216
|
-
assert(exists == true, 'Editor does not exist!')
|
|
2217
|
-
ao.send({
|
|
2218
|
-
Target = msg.From,
|
|
2219
|
-
Data = "editor removed!",
|
|
2220
|
-
Tags = {
|
|
2221
|
-
Editors = json.encode(editors)
|
|
2222
|
-
|
|
2223
|
-
}
|
|
2224
|
-
})
|
|
2225
|
-
end
|
|
2226
|
-
)
|
|
2227
|
-
|
|
2228
|
-
Handlers.add(
|
|
2229
|
-
"update",
|
|
2230
|
-
Handlers.utils.hasMatchingTag("Action", "Update"),
|
|
2231
|
-
function (msg)
|
|
2232
|
-
local ver = msg.Tags.Version
|
|
2233
|
-
assert(type(ver) == "string", 'Version is required!')
|
|
2234
|
-
assert(type(msg.Data) == "string", 'Data is required!')
|
|
2235
|
-
assert(is_editor(msg.From), 'sender is not an editor!')
|
|
2236
|
-
if ver == "major" then
|
|
2237
|
-
version = tostring(semver(version):nextMajor())
|
|
2238
|
-
elseif ver == "minor" then
|
|
2239
|
-
version = tostring(semver(version):nextMinor())
|
|
2240
|
-
elseif ver == "patch" then
|
|
2241
|
-
version = tostring(semver(version):nextPatch())
|
|
2242
|
-
else
|
|
2243
|
-
assert(semver(ver) > semver(version), "Version must be higher!")
|
|
2244
|
-
version = ver
|
|
2245
|
-
end
|
|
2246
|
-
local _patches = dmp.patch_fromText(base64.decode(msg.Data))
|
|
2247
|
-
data = dmp.patch_apply(_patches, data)
|
|
2248
|
-
table.insert(versions, { version = msg.Tags.Version, date = msg.Timestamp, patches = msg.Data, editor = msg.From })
|
|
2249
|
-
Handlers.utils.reply("updated!")(msg)
|
|
2250
|
-
end
|
|
2251
|
-
)
|
|
2252
|
-
|
|
2253
|
-
Handlers.add(
|
|
2254
|
-
"patches",
|
|
2255
|
-
Handlers.utils.hasMatchingTag("Action", "Patches"),
|
|
2256
|
-
function (msg)
|
|
2257
|
-
local patches = dmp.patch_make(data, msg.Data)
|
|
2258
|
-
ao.send({
|
|
2259
|
-
Target = msg.From,
|
|
2260
|
-
Tags = {
|
|
2261
|
-
Patches = base64.encode(dmp.patch_toText(patches)),
|
|
2262
|
-
}
|
|
2263
|
-
})
|
|
2264
|
-
end
|
|
2265
|
-
)
|
|
2266
|
-
|
|
2267
|
-
Handlers.add(
|
|
2268
|
-
"assigned",
|
|
2269
|
-
Handlers.utils.hasMatchingTag("Action", "Assigned"),
|
|
2270
|
-
function (msg)
|
|
2271
|
-
data = msg.Data
|
|
2272
|
-
table.insert(versions, { version = version, date = nil, patches = nil, editor = ao.env.Process.Owner })
|
|
2273
|
-
end
|
|
2274
|
-
)
|