summaryrefslogtreecommitdiff
path: root/script
diff options
context:
space:
mode:
author最萌小汐 <sumneko@hotmail.com>2022-01-10 20:11:13 +0800
committer最萌小汐 <sumneko@hotmail.com>2022-01-10 20:11:24 +0800
commit1b068299839ba6f8e35bbc87b56d5198580f14fd (patch)
treef5c8cad6e377054742aa3cdf1079cb9c28f94ef1 /script
parent88ff10963544879fa990f2df72651159758fcd75 (diff)
downloadlua-language-server-1b068299839ba6f8e35bbc87b56d5198580f14fd.zip
resolve multilines and overlapping
Diffstat (limited to 'script')
-rw-r--r--script/core/semantic-tokens.lua94
-rw-r--r--script/linked-table.lua193
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