Skip to content

Commit 1b06829

Browse files
committed
resolve multilines and overlapping
1 parent 88ff109 commit 1b06829

File tree

2 files changed

+284
-3
lines changed

2 files changed

+284
-3
lines changed

script/core/semantic-tokens.lua

Lines changed: 91 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ local guide = require 'parser.guide'
88
local converter = require 'proto.converter'
99
local infer = require 'core.infer'
1010
local config = require 'config'
11+
local linkedTable = require 'linked-table'
1112

1213
local Care = util.switch()
1314
: case 'getglobal'
@@ -411,6 +412,91 @@ local function buildTokens(uri, results)
411412
return tokens
412413
end
413414

415+
---@async
416+
local function solveMultilineAndOverlapping(state, results)
417+
table.sort(results, function (a, b)
418+
if a.start == b.start then
419+
return a.finish < b.finish
420+
else
421+
return a.start < b.start
422+
end
423+
end)
424+
425+
await.delay()
426+
427+
local tokens = linkedTable()
428+
429+
local function findToken(pos)
430+
for token in tokens:pairs(nil ,true) do
431+
if token.start <= pos and token.finish >= pos then
432+
return token
433+
end
434+
if token.finish < pos then
435+
break
436+
end
437+
end
438+
return nil
439+
end
440+
441+
for _, current in ipairs(results) do
442+
local left = findToken(current.start)
443+
if not left then
444+
tokens:pushTail(current)
445+
goto CONTINUE
446+
end
447+
local right = findToken(current.finish)
448+
tokens:pushAfter(current, left)
449+
tokens:pop(left)
450+
if left.start < current.start then
451+
tokens:pushBefore({
452+
start = left.start,
453+
finish = current.start,
454+
type = left.type,
455+
modifieres = left.modifieres
456+
}, current)
457+
end
458+
if right and right.finish > current.finish then
459+
tokens:pushAfter({
460+
start = current.finish,
461+
finish = right.finish,
462+
type = right.type,
463+
modifieres = right.modifieres
464+
}, current)
465+
end
466+
::CONTINUE::
467+
end
468+
469+
await.delay()
470+
471+
local new = {}
472+
for token in tokens:pairs() do
473+
new[#new+1] = token
474+
local startRow, startCol = guide.rowColOf(token.start)
475+
local finishRow, finishCol = guide.rowColOf(token.finish)
476+
if finishRow > startRow then
477+
token.finish = guide.positionOf(startRow, 9999)
478+
end
479+
for i = startRow + 1, finishRow - 1 do
480+
new[#new+1] = {
481+
start = guide.positionOf(i, 0),
482+
finish = guide.positionOf(i, 9999),
483+
type = token.type,
484+
modifieres = token.modifieres,
485+
}
486+
end
487+
if finishCol > 0 then
488+
new[#new+1] = {
489+
start = guide.positionOf(finishRow, 0),
490+
finish = token.finish,
491+
type = token.type,
492+
modifieres = token.modifieres,
493+
}
494+
end
495+
end
496+
497+
return new
498+
end
499+
414500
---@async
415501
return function (uri, start, finish)
416502
if config.get(uri, 'Lua.color.mode') == 'Grammar' then
@@ -448,9 +534,11 @@ return function (uri, start, finish)
448534
end
449535
end
450536

451-
table.sort(results, function (a, b)
452-
return a.start < b.start
453-
end)
537+
if #results == 0 then
538+
return nil
539+
end
540+
541+
results = solveMultilineAndOverlapping(state, results)
454542

455543
local tokens = buildTokens(uri, results)
456544

script/linked-table.lua

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
---@class linked-table
2+
---@field _left table
3+
---@field _right table
4+
local mt = {}
5+
mt.__index = mt
6+
mt._size = 0
7+
8+
local HEAD = {'<HEAD>'}
9+
local TAIL = {'<TAIL>'}
10+
11+
function mt:has(node)
12+
return self._left[node] ~= nil
13+
end
14+
15+
function mt:isValidNode(node)
16+
if node == nil
17+
or node == HEAD
18+
or node == TAIL then
19+
return false
20+
end
21+
return true
22+
end
23+
24+
function mt:pushAfter(node, afterWho)
25+
if not self:isValidNode(node) then
26+
return false
27+
end
28+
if self:has(node) then
29+
return false
30+
end
31+
local right = self._right[afterWho]
32+
if not right then
33+
return false
34+
end
35+
self._right[afterWho] = node
36+
self._right[node] = right
37+
self._left[right] = node
38+
self._left[node] = afterWho
39+
40+
self._size = self._size + 1
41+
return true
42+
end
43+
44+
function mt:pushBefore(node, beforeWho)
45+
if node == nil then
46+
return false
47+
end
48+
local left = self._left[beforeWho]
49+
if not left then
50+
return false
51+
end
52+
return self:pushAfter(node, left)
53+
end
54+
55+
function mt:pop(node)
56+
if not self:isValidNode(node) then
57+
return false
58+
end
59+
local left = self._left[node]
60+
if not left then
61+
return false
62+
end
63+
local right = self._right[node]
64+
self._right[left] = right
65+
self._left[right] = left
66+
67+
self._right[node] = nil
68+
self._left[node] = nil
69+
70+
self._size = self._size - 1
71+
return true
72+
end
73+
74+
function mt:pushHead(node)
75+
return self:pushAfter(node, HEAD)
76+
end
77+
78+
function mt:pushTail(node)
79+
return self:pushBefore(node, TAIL)
80+
end
81+
82+
function mt:getAfter(node)
83+
if node == nil then
84+
node = HEAD
85+
end
86+
local right = self._right[node]
87+
if right == TAIL then
88+
return nil
89+
end
90+
return right
91+
end
92+
93+
function mt:getHead()
94+
return self:getAfter(HEAD)
95+
end
96+
97+
function mt:getBefore(node)
98+
if node == nil then
99+
node = TAIL
100+
end
101+
local left = self._left[node]
102+
if left == HEAD then
103+
return nil
104+
end
105+
return left
106+
end
107+
108+
function mt:getTail()
109+
return self:getBefore(TAIL)
110+
end
111+
112+
function mt:popHead()
113+
return self:pop(self:getHead())
114+
end
115+
116+
function mt:popTail()
117+
return self:pop(self:getTail())
118+
end
119+
120+
function mt:replace(old, new)
121+
if not self:isValidNode(old)
122+
or not self:isValidNode(new) then
123+
return false
124+
end
125+
local left = self._left[old]
126+
if not left then
127+
return false
128+
end
129+
local right = self._right[old]
130+
self._right[left] = new
131+
self._right[new] = right
132+
self._left[right] = new
133+
self._left[new] = left
134+
135+
self._right[old] = nil
136+
self._left[old] = nil
137+
return true
138+
end
139+
140+
function mt:getSize()
141+
return self._size
142+
end
143+
144+
function mt:pairs(start, revert)
145+
if revert then
146+
if start == nil then
147+
start = self._left[TAIL]
148+
end
149+
local next = start
150+
return function ()
151+
local current = next
152+
if current == HEAD then
153+
return nil
154+
end
155+
next = self._left[current]
156+
return current
157+
end
158+
else
159+
if start == nil then
160+
start = self._right[HEAD]
161+
end
162+
local next = start
163+
return function ()
164+
local current = next
165+
if current == TAIL then
166+
return nil
167+
end
168+
next = self._right[current]
169+
return current
170+
end
171+
end
172+
end
173+
174+
function mt:dump(start, revert)
175+
local t = {}
176+
for node in self:pairs(start, revert) do
177+
t[#t+1] = tostring(node)
178+
end
179+
return table.concat(t, ' ')
180+
end
181+
182+
function mt:reset()
183+
self._left = { [TAIL] = HEAD }
184+
self._right = { [HEAD] = TAIL }
185+
186+
self._size = 0
187+
end
188+
189+
return function ()
190+
local self = setmetatable({}, mt)
191+
self:reset()
192+
return self
193+
end

0 commit comments

Comments
 (0)