summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author最萌小汐 <sumneko@hotmail.com>2021-01-22 18:40:27 +0800
committer最萌小汐 <sumneko@hotmail.com>2021-01-22 18:40:27 +0800
commitaaa26c3d7259319359565a77287a923c0822bba9 (patch)
tree128a8e513574952f882ed4077ff5783884477d1a
parent489fcbaa9da91ac8275a2ba5dadc6bd88b9cd5ec (diff)
downloadlua-language-server-aaa26c3d7259319359565a77287a923c0822bba9.zip
stash
-rw-r--r--script/files.lua34
-rw-r--r--script/parser/guide.lua2
-rw-r--r--script/string-merger.lua102
3 files changed, 133 insertions, 5 deletions
diff --git a/script/files.lua b/script/files.lua
index d5ff5981..679aa0cb 100644
--- a/script/files.lua
+++ b/script/files.lua
@@ -10,6 +10,7 @@ local timer = require 'timer'
local plugin = require 'plugin'
local util = require 'utility'
local guide = require 'parser.guide'
+local smerger = require 'string-merger'
local m = {}
@@ -97,6 +98,34 @@ function m.asKey(uri)
return uri
end
+function m.setDiffInfo(uri, info)
+ uri = getUriKey(uri)
+ local file = m.fileMap[uri]
+ if not file then
+ return
+ end
+ file._diffInfo = info
+end
+
+local function pluginOnSetText(uri, text)
+ m.setDiffInfo(nil)
+ local suc, result = plugin.dispatch('OnSetText', uri, text)
+ if not suc then
+ return text
+ end
+ if type(result) == 'string' then
+ return result
+ elseif type(result) == 'table' then
+ local diffs
+ suc, result, diffs = xpcall(smerger.mergeDiff, log.warn, text, result)
+ if suc then
+ m.setDiffInfo(diffs)
+ return result
+ end
+ end
+ return text
+end
+
--- 设置文件文本
---@param uri uri
---@param text string
@@ -116,10 +145,7 @@ function m.setText(uri, text)
create = true
m._pairsCache = nil
end
- local suc, newText = plugin.dispatch('OnSetText', originUri, text)
- if not suc then
- newText = text
- end
+ local newText = pluginOnSetText(originUri, text)
local file = m.fileMap[uri]
if file.text == newText then
return
diff --git a/script/parser/guide.lua b/script/parser/guide.lua
index 5f1bc230..5e4652b3 100644
--- a/script/parser/guide.lua
+++ b/script/parser/guide.lua
@@ -1370,7 +1370,7 @@ function m.getCallValue(source)
end
if call.node.special == 'pcall'
or call.node.special == 'xpcall' then
- return call.args[1], call.args, index - 1
+ return call.args and call.args[1], call.args, index - 1
end
return call.node, call.args, index
end
diff --git a/script/string-merger.lua b/script/string-merger.lua
new file mode 100644
index 00000000..e6650f04
--- /dev/null
+++ b/script/string-merger.lua
@@ -0,0 +1,102 @@
+---@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
+function m.getOffset(info, offset)
+ local diff = getNearDiff(info, offset, 'start')
+ if offset <= diff.finish then
+ return diff.cstart
+ end
+ return offset - diff.finish + diff.cfinish
+end
+
+---根据转换后的位置获取转换前的位置
+---@param info string.merger.infos
+---@param offset integer
+---@return integer
+function m.getOffsetBack(info, offset)
+ local diff = getNearDiff(info, offset, 'cstart')
+ if offset <= diff.cfinish then
+ return diff.start
+ end
+ return offset - diff.cfinish + diff.finish
+end
+
+return m