diff options
author | 最萌小汐 <sumneko@hotmail.com> | 2022-01-10 20:11:13 +0800 |
---|---|---|
committer | 最萌小汐 <sumneko@hotmail.com> | 2022-01-10 20:11:24 +0800 |
commit | 1b068299839ba6f8e35bbc87b56d5198580f14fd (patch) | |
tree | f5c8cad6e377054742aa3cdf1079cb9c28f94ef1 /script | |
parent | 88ff10963544879fa990f2df72651159758fcd75 (diff) | |
download | lua-language-server-1b068299839ba6f8e35bbc87b56d5198580f14fd.zip |
resolve multilines and overlapping
Diffstat (limited to 'script')
-rw-r--r-- | script/core/semantic-tokens.lua | 94 | ||||
-rw-r--r-- | script/linked-table.lua | 193 |
2 files changed, 284 insertions, 3 deletions
diff --git a/script/core/semantic-tokens.lua b/script/core/semantic-tokens.lua index 2a77f17f..b4b05149 100644 --- a/script/core/semantic-tokens.lua +++ b/script/core/semantic-tokens.lua @@ -8,6 +8,7 @@ local guide = require 'parser.guide' local converter = require 'proto.converter' local infer = require 'core.infer' local config = require 'config' +local linkedTable = require 'linked-table' local Care = util.switch() : case 'getglobal' @@ -412,6 +413,91 @@ local function buildTokens(uri, results) end ---@async +local function solveMultilineAndOverlapping(state, results) + table.sort(results, function (a, b) + if a.start == b.start then + return a.finish < b.finish + else + return a.start < b.start + end + end) + + await.delay() + + local tokens = linkedTable() + + local function findToken(pos) + for token in tokens:pairs(nil ,true) do + if token.start <= pos and token.finish >= pos then + return token + end + if token.finish < pos then + break + end + end + return nil + end + + for _, current in ipairs(results) do + local left = findToken(current.start) + if not left then + tokens:pushTail(current) + goto CONTINUE + end + local right = findToken(current.finish) + tokens:pushAfter(current, left) + tokens:pop(left) + if left.start < current.start then + tokens:pushBefore({ + start = left.start, + finish = current.start, + type = left.type, + modifieres = left.modifieres + }, current) + end + if right and right.finish > current.finish then + tokens:pushAfter({ + start = current.finish, + finish = right.finish, + type = right.type, + modifieres = right.modifieres + }, current) + end + ::CONTINUE:: + end + + await.delay() + + local new = {} + for token in tokens:pairs() do + new[#new+1] = token + local startRow, startCol = guide.rowColOf(token.start) + local finishRow, finishCol = guide.rowColOf(token.finish) + if finishRow > startRow then + token.finish = guide.positionOf(startRow, 9999) + end + for i = startRow + 1, finishRow - 1 do + new[#new+1] = { + start = guide.positionOf(i, 0), + finish = guide.positionOf(i, 9999), + type = token.type, + modifieres = token.modifieres, + } + end + if finishCol > 0 then + new[#new+1] = { + start = guide.positionOf(finishRow, 0), + finish = token.finish, + type = token.type, + modifieres = token.modifieres, + } + end + end + + return new +end + +---@async return function (uri, start, finish) if config.get(uri, 'Lua.color.mode') == 'Grammar' then return nil @@ -448,9 +534,11 @@ return function (uri, start, finish) end end - table.sort(results, function (a, b) - return a.start < b.start - end) + if #results == 0 then + return nil + end + + results = solveMultilineAndOverlapping(state, results) local tokens = buildTokens(uri, results) diff --git a/script/linked-table.lua b/script/linked-table.lua new file mode 100644 index 00000000..4d87e943 --- /dev/null +++ b/script/linked-table.lua @@ -0,0 +1,193 @@ +---@class linked-table +---@field _left table +---@field _right table +local mt = {} +mt.__index = mt +mt._size = 0 + +local HEAD = {'<HEAD>'} +local TAIL = {'<TAIL>'} + +function mt:has(node) + return self._left[node] ~= nil +end + +function mt:isValidNode(node) + if node == nil + or node == HEAD + or node == TAIL then + return false + end + return true +end + +function mt:pushAfter(node, afterWho) + if not self:isValidNode(node) then + return false + end + if self:has(node) then + return false + end + local right = self._right[afterWho] + if not right then + return false + end + self._right[afterWho] = node + self._right[node] = right + self._left[right] = node + self._left[node] = afterWho + + self._size = self._size + 1 + return true +end + +function mt:pushBefore(node, beforeWho) + if node == nil then + return false + end + local left = self._left[beforeWho] + if not left then + return false + end + return self:pushAfter(node, left) +end + +function mt:pop(node) + if not self:isValidNode(node) then + return false + end + local left = self._left[node] + if not left then + return false + end + local right = self._right[node] + self._right[left] = right + self._left[right] = left + + self._right[node] = nil + self._left[node] = nil + + self._size = self._size - 1 + return true +end + +function mt:pushHead(node) + return self:pushAfter(node, HEAD) +end + +function mt:pushTail(node) + return self:pushBefore(node, TAIL) +end + +function mt:getAfter(node) + if node == nil then + node = HEAD + end + local right = self._right[node] + if right == TAIL then + return nil + end + return right +end + +function mt:getHead() + return self:getAfter(HEAD) +end + +function mt:getBefore(node) + if node == nil then + node = TAIL + end + local left = self._left[node] + if left == HEAD then + return nil + end + return left +end + +function mt:getTail() + return self:getBefore(TAIL) +end + +function mt:popHead() + return self:pop(self:getHead()) +end + +function mt:popTail() + return self:pop(self:getTail()) +end + +function mt:replace(old, new) + if not self:isValidNode(old) + or not self:isValidNode(new) then + return false + end + local left = self._left[old] + if not left then + return false + end + local right = self._right[old] + self._right[left] = new + self._right[new] = right + self._left[right] = new + self._left[new] = left + + self._right[old] = nil + self._left[old] = nil + return true +end + +function mt:getSize() + return self._size +end + +function mt:pairs(start, revert) + if revert then + if start == nil then + start = self._left[TAIL] + end + local next = start + return function () + local current = next + if current == HEAD then + return nil + end + next = self._left[current] + return current + end + else + if start == nil then + start = self._right[HEAD] + end + local next = start + return function () + local current = next + if current == TAIL then + return nil + end + next = self._right[current] + return current + end + end +end + +function mt:dump(start, revert) + local t = {} + for node in self:pairs(start, revert) do + t[#t+1] = tostring(node) + end + return table.concat(t, ' ') +end + +function mt:reset() + self._left = { [TAIL] = HEAD } + self._right = { [HEAD] = TAIL } + + self._size = 0 +end + +return function () + local self = setmetatable({}, mt) + self:reset() + return self +end |