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
|
local files = require 'files'
local util = require 'utility'
local encoder = require 'encoder'
local client = require 'client'
local offsetEncoding
local function getOffsetEncoding()
if not offsetEncoding then
offsetEncoding = client.getOffsetEncoding():lower():gsub('%-', '')
end
return offsetEncoding
end
local function splitRows(text)
local rows = {}
for line in util.eachLine(text, true) do
rows[#rows+1] = line
end
return rows
end
local function getLeft(text, char)
if not text then
return ''
end
local encoding = getOffsetEncoding()
local left
local length = encoder.len(encoding, text)
if char == 0 then
left = ''
elseif char >= length then
left = text
else
left = text:sub(1, encoder.offset(encoding, text, char + 1) - 1)
end
return left
end
local function getRight(text, char)
if not text then
return ''
end
local encoding = getOffsetEncoding()
local right
local length = encoder.len(encoding, text)
if char == 0 then
right = text
elseif char >= length then
right = ''
else
right = text:sub(encoder.offset(encoding, text, char + 1))
end
return right
end
local function mergeRows(rows, change)
local startLine = change.range['start'].line + 1
local startChar = change.range['start'].character
local endLine = change.range['end'].line + 1
local endChar = change.range['end'].character
local insertRows = splitRows(change.text)
local newEndLine = startLine + #insertRows - 1
local left = getLeft(rows[startLine], startChar)
local right = getRight(rows[endLine], endChar)
-- 先把双方的行数调整成一致
if endLine > #rows then
log.error('NMD, WSM `endLine > #rows` ?')
for i = #rows + 1, endLine do
rows[i] = ''
end
end
local delta = #insertRows - (endLine - startLine + 1)
if delta ~= 0 then
table.move(rows, endLine, #rows, endLine + delta)
-- 如果行数变少了,要清除多余的行
if delta < 0 then
for i = #rows, #rows + delta + 1, -1 do
rows[i] = nil
end
end
end
-- 先处理第一行和最后一行
if startLine == newEndLine then
rows[startLine] = left .. insertRows[1] .. right
else
rows[startLine] = left .. insertRows[1]
rows[newEndLine] = insertRows[#insertRows] .. right
end
-- 修改中间的每一行
for i = 2, #insertRows - 1 do
local currentLine = startLine + i - 1
local insertText = insertRows[i] or ''
rows[currentLine] = insertText
end
end
return function (text, rows, changes)
for _, change in ipairs(changes) do
if change.range then
rows = rows or splitRows(text)
mergeRows(rows, change)
else
rows = nil
text = change.text
end
end
if rows then
text = table.concat(rows)
end
return text, rows
end
|