diff options
author | 最萌小汐 <sumneko@hotmail.com> | 2021-03-12 17:03:03 +0800 |
---|---|---|
committer | 最萌小汐 <sumneko@hotmail.com> | 2021-03-12 17:03:03 +0800 |
commit | 3517513487ab039bf704938d03897686c3f6d6ad (patch) | |
tree | ea5a09e2137447a1a132ebb3524d02ca2fad83a4 | |
parent | 6b7a952d6537f389a85df7928ded74ca9c81eee0 (diff) | |
parent | 062bb1ce750a4a7a37b38452b9cf196c491cc6e5 (diff) | |
download | lua-language-server-3517513487ab039bf704938d03897686c3f6d6ad.zip |
Merge branch 'text-merger'
-rw-r--r-- | changelog.md | 1 | ||||
-rw-r--r-- | script/files.lua | 30 | ||||
-rw-r--r-- | script/parser/guide.lua | 5 | ||||
-rw-r--r-- | script/provider/provider.lua | 15 | ||||
-rw-r--r-- | script/service/service.lua | 22 | ||||
-rw-r--r-- | script/text-merger.lua | 99 | ||||
-rw-r--r-- | script/utility.lua | 25 | ||||
-rw-r--r-- | test/basic/init.lua | 132 | ||||
-rw-r--r-- | test/crossfile/definition.lua | 4 |
9 files changed, 279 insertions, 54 deletions
diff --git a/changelog.md b/changelog.md index c2749cd0..ee1e265e 100644 --- a/changelog.md +++ b/changelog.md @@ -1,6 +1,7 @@ # changelog ## 1.19.0 +* `CHG` text-document-synchronization: refactored * `FIX` missed syntax error `function m['x']() end` ## 1.18.1 diff --git a/script/files.lua b/script/files.lua index b085e7fd..3f3d633e 100644 --- a/script/files.lua +++ b/script/files.lua @@ -19,6 +19,7 @@ if platform.OS == 'Windows' then unicode = require 'bee.unicode' end +---@class files local m = {} m.openMap = {} @@ -206,6 +207,24 @@ function m.setRawText(uri, text) m.astMap[uri] = nil end +function m.getCachedRows(uri) + uri = getUriKey(uri) + local file = m.fileMap[uri] + if not file then + return nil + end + return file.rows +end + +function m.setCachedRows(uri, rows) + uri = getUriKey(uri) + local file = m.fileMap[uri] + if not file then + return + end + file.rows = rows +end + --- 获取文件版本 function m.getVersion(uri) uri = getUriKey(uri) @@ -633,17 +652,6 @@ function m.diffedOffsetBack(uri, offset) return smerger.getOffsetBack(file._diffInfo, offset) end -function m.clearDiff(uri) - uri = m.getUri(uri) - local file = m.fileMap[uri] - if not file then - return - end - file._diffInfo = nil - file.text = file.originText - m.linesMap[uri] = m.originLinesMap[uri] -end - --- 将光标位置转化为 position ---@param uri uri ---@param offset integer diff --git a/script/parser/guide.lua b/script/parser/guide.lua index 81adf890..377b2823 100644 --- a/script/parser/guide.lua +++ b/script/parser/guide.lua @@ -2404,6 +2404,7 @@ function m.searchSameFieldsInValue(status, ref, start, pushQueue, mode) if not m.checkValueMark(status, ref, value) then --return end + status.share.inSetValue = (status.share.inSetValue or 0) + 1 if not status.share.tempValueMark then status.share.tempValueMark = {} end @@ -2417,6 +2418,7 @@ function m.searchSameFieldsInValue(status, ref, start, pushQueue, mode) end pushQueue(value, start, true) end + status.share.inSetValue = (status.share.inSetValue or 0) - 1 -- 检查形如 a = f() 的分支情况 m.checkSameSimpleInCall(status, value, start, pushQueue, mode) end @@ -2475,6 +2477,9 @@ function m.checkSameSimpleAsSetValue(status, ref, start, pushQueue) if not status.deep then --return end + if status.share.inSetValue and status.share.inSetValue > 0 then + return + end if ref.type == 'select' then return end diff --git a/script/provider/provider.lua b/script/provider/provider.lua index 917f66cc..66031f15 100644 --- a/script/provider/provider.lua +++ b/script/provider/provider.lua @@ -17,6 +17,7 @@ local fs = require 'bee.filesystem' local lang = require 'language' local plugin = require 'plugin' local progress = require 'progress' +local tm = require 'text-merger' local function updateConfig() local diagnostics = require 'provider.diagnostic' @@ -270,18 +271,8 @@ proto.on('textDocument/didChange', function (params) if not files.isLua(uri) and not files.isOpen(uri) then return end - files.clearDiff(uri) - local text = files.getText(uri) or '' - for _, change in ipairs(changes) do - if change.range then - local start, finish = files.unrange(uri, change.range) - text = text:sub(1, start - 1) .. change.text .. text:sub(finish) - else - text = change.text - end - files.setRawText(uri, text) - end - files.setRawText(uri, '') + --log.debug('changes', util.dump(changes)) + local text = tm(uri, changes) files.setText(uri, text, true) end) diff --git a/script/service/service.lua b/script/service/service.lua index 14f05ada..44fd9aa4 100644 --- a/script/service/service.lua +++ b/script/service/service.lua @@ -141,16 +141,15 @@ end function m.startTimer() pub.task('timer', 1) while true do - pub.step(not m.working) + pub.step(not m.workingClock) if await.step() then m.sleeping = false - if not m.working then - m.working = true - m.reportStatus() + if not m.workingClock then + m.workingClock = time.monotonic() end else - if m.working then - m.working = false + if m.workingClock then + m.workingClock = nil m.idleClock = time.monotonic() m.reportStatus() end @@ -159,9 +158,9 @@ function m.startTimer() end end -function m.checkSleep() +function m.pulse() timer.loop(10, function () - if not m.working and not m.sleeping and time.monotonic() - m.idleClock >= 300000 then + if not m.workingClock and not m.sleeping and time.monotonic() - m.idleClock >= 300000 then m.sleeping = true files.flushCache() vm.flushCache() @@ -171,11 +170,14 @@ function m.checkSleep() end m.reportStatus() end) + timer.loop(0.1, function () + m.reportStatus() + end) end function m.reportStatus() local info = {} - if m.working then + if m.workingClock and time.monotonic() - m.workingClock > 100 then info.text = '$(loading~spin)Lua' elseif m.sleeping then info.text = "💤Lua" @@ -212,7 +214,7 @@ function m.start() pub.recruitBraves(4) proto.listen() m.report() - m.checkSleep() + m.pulse() m.reportStatus() m.testVersion() diff --git a/script/text-merger.lua b/script/text-merger.lua new file mode 100644 index 00000000..aa124fdd --- /dev/null +++ b/script/text-merger.lua @@ -0,0 +1,99 @@ +local files = require 'files' +local util = require 'utility' + +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) + local left + local length = util.utf8Len(text) + + if char == 0 then + left = '' + elseif char >= length then + left = text + else + left = text:sub(1, utf8.offset(text, char + 1) - 1) + end + + return left +end + +local function getRight(text, char) + local right + local length = util.utf8Len(text) + + if char == 0 then + right = text + elseif char >= length then + right = '' + else + right = text:sub(utf8.offset(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) + -- 先把双方的行数调整成一致 + 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] + rows[currentLine] = insertText + end +end + +return function (uri, changes) + local text + for _, change in ipairs(changes) do + if change.range then + local rows = files.getCachedRows(uri) + if not rows then + text = text or files.getOriginText(uri) + rows = splitRows(text) + end + mergeRows(rows, change) + files.setCachedRows(uri, rows) + else + files.setCachedRows(uri, nil) + text = change.text + end + end + local rows = files.getCachedRows(uri) + if rows then + text = table.concat(rows) + end + return text +end diff --git a/script/utility.lua b/script/utility.lua index a1eec7eb..a98bef92 100644 --- a/script/utility.lua +++ b/script/utility.lua @@ -547,24 +547,43 @@ function m.tableMultiRemove(t, index) end end -function m.eachLine(text) +---遍历文本的每一行 +---@param text string +---@param keepNL boolean # 保留换行符 +---@return fun(text:string):string +function m.eachLine(text, keepNL) local offset = 1 local lineCount = 0 + local lastLine return function () if offset > #text then + if not lastLine then + lastLine = '' + return '' + end return nil end lineCount = lineCount + 1 local nl = text:find('[\r\n]', offset) if not nl then - local lastLine = text:sub(offset) + lastLine = text:sub(offset) offset = #text + 1 return lastLine end - local line = text:sub(offset, nl - 1) + local line if text:sub(nl, nl + 1) == '\r\n' then + if keepNL then + line = text:sub(offset, nl + 1) + else + line = text:sub(offset, nl - 1) + end offset = nl + 2 else + if keepNL then + line = text:sub(offset, nl) + else + line = text:sub(offset, nl - 1) + end offset = nl + 1 end return line diff --git a/test/basic/init.lua b/test/basic/init.lua index f809a2f3..a3a11f62 100644 --- a/test/basic/init.lua +++ b/test/basic/init.lua @@ -1,15 +1,31 @@ local files = require 'files' +local tm = require 'text-merger' -local text = [[ +local function TEST(source) + return function (expect) + return function (changes) + files.removeAll() + files.setText('', source) + local text = tm('', changes) + assert(text == expect) + end + end +end + +TEST [[ + + +function Test(self) + +end +]][[ function Test(self) end -]] -files.setText('', text) -local changes = { +asser]]{ [1] = { range = { ["end"] = { @@ -97,21 +113,107 @@ local changes = { }, } -for _, change in ipairs(changes) do - if change.range then - local start, finish = files.unrange('', change.range) - text = text:sub(1, start - 1) .. change.text .. text:sub(finish) - else - text = change.text - end - files.setRawText('', text) +TEST [[ +local mt = {} + +function mt['xxx']() + + + end +]] [[ +local mt = {} -assert(text == [[ +function mt['xxx']() + +end +]] { + [1] = { + range = { + ["end"] = { + character = 4, + line = 5, + }, + start = { + character = 4, + line = 3, + }, + }, + rangeLength = 8, + text = "", + }, +} +TEST [[ +local mt = {} -function Test(self) +function mt['xxx']() + +end +]] [[ +local mt = {} +function mt['xxx']() + p end +]] { + [1] = { + range = { + ["end"] = { + character = 4, + line = 3, + }, + start = { + character = 4, + line = 3, + }, + }, + rangeLength = 0, + text = "p", + }, +} + +TEST [[ +print(12345) +]] [[ +print(123 +45) +]] { + [1] = { + range = { + ["end"] = { + character = 9, + line = 0, + }, + start = { + character = 9, + line = 0, + }, + }, + rangeLength = 0, + text = "\ +", + }, +} -asser]]) +TEST [[ +print(123 +45) +]] [[ +print(12345) +]] { + [1] = { + range = { + ["end"] = { + character = 0, + line = 1, + }, + start = { + character = 9, + line = 0, + }, + }, + rangeLength = 2, + text = "", + }, +} diff --git a/test/crossfile/definition.lua b/test/crossfile/definition.lua index 9ee90de2..24c97321 100644 --- a/test/crossfile/definition.lua +++ b/test/crossfile/definition.lua @@ -564,9 +564,7 @@ TEST { { path = 'a.lua', content = [[ - local t = GlobalTable - - t.settings = { + GlobalTable.settings = { <!test!> = 1 } ]], |