157 lines
4.1 KiB
Lua
157 lines
4.1 KiB
Lua
local guide = require 'parser.guide'
|
||
local files = require 'files'
|
||
local vm = require 'vm'
|
||
local findSource = require 'core.find-source'
|
||
local jumpSource = require 'core.jump-source'
|
||
|
||
local function sortResults(results)
|
||
-- 先按照顺序排序
|
||
table.sort(results, function (a, b)
|
||
local u1 = guide.getUri(a.target)
|
||
local u2 = guide.getUri(b.target)
|
||
if u1 == u2 then
|
||
return a.target.start < b.target.start
|
||
else
|
||
return u1 < u2
|
||
end
|
||
end)
|
||
-- 如果2个结果处于嵌套状态,则取范围小的那个
|
||
local lf, lu
|
||
for i = #results, 1, -1 do
|
||
local res = results[i].target
|
||
local f = res.finish
|
||
local uri = guide.getUri(res)
|
||
if lf and f > lf and uri == lu then
|
||
table.remove(results, i)
|
||
else
|
||
lu = uri
|
||
lf = f
|
||
end
|
||
end
|
||
end
|
||
|
||
local accept = {
|
||
['local'] = true,
|
||
['setlocal'] = true,
|
||
['getlocal'] = true,
|
||
['label'] = true,
|
||
['goto'] = true,
|
||
['field'] = true,
|
||
['method'] = true,
|
||
['setindex'] = true,
|
||
['getindex'] = true,
|
||
['tableindex'] = true,
|
||
['setglobal'] = true,
|
||
['getglobal'] = true,
|
||
['function'] = true,
|
||
['...'] = true,
|
||
|
||
['doc.type.name'] = true,
|
||
['doc.class.name'] = true,
|
||
['doc.extends.name'] = true,
|
||
['doc.alias.name'] = true,
|
||
['doc.enum.name'] = true,
|
||
['doc.field.name'] = true,
|
||
}
|
||
|
||
---@async
|
||
---@param uri uri
|
||
---@param position integer
|
||
---@param includeDeclaration boolean
|
||
return function (uri, position, includeDeclaration)
|
||
local ast = files.getState(uri)
|
||
if not ast then
|
||
return nil
|
||
end
|
||
|
||
local source = findSource(ast, position, accept)
|
||
if not source then
|
||
return nil
|
||
end
|
||
|
||
local metaSource = vm.isMetaFile(uri)
|
||
|
||
local refs = vm.getRefs(source)
|
||
|
||
local results = {}
|
||
for _, src in ipairs(refs) do
|
||
local root = guide.getRoot(src)
|
||
if not root then
|
||
goto CONTINUE
|
||
end
|
||
if not metaSource and vm.isMetaFile(root.uri) then
|
||
goto CONTINUE
|
||
end
|
||
if src.type == 'self' then
|
||
goto CONTINUE
|
||
end
|
||
if not includeDeclaration and guide.isSet(src) then
|
||
goto CONTINUE
|
||
end
|
||
src = src.field or src.method or src
|
||
if src.type == 'getindex'
|
||
or src.type == 'setindex'
|
||
or src.type == 'tableindex' then
|
||
src = src.index
|
||
if not src then
|
||
goto CONTINUE
|
||
end
|
||
if not guide.isLiteral(src) then
|
||
goto CONTINUE
|
||
end
|
||
else
|
||
if guide.isLiteral(src) and src.type ~= 'function' then
|
||
goto CONTINUE
|
||
end
|
||
end
|
||
if src.type == 'doc.class' then
|
||
src = src.class
|
||
end
|
||
if src.type == 'doc.alias' then
|
||
src = src.alias
|
||
end
|
||
if src.type == 'doc.enum' then
|
||
src = src.enum
|
||
end
|
||
if src.type == 'doc.type.field' then
|
||
src = src.name
|
||
end
|
||
if src.type == 'doc.class.name'
|
||
or src.type == 'doc.alias.name'
|
||
or src.type == 'doc.enum.name'
|
||
or src.type == 'doc.type.name'
|
||
or src.type == 'doc.extends.name' then
|
||
if source.type ~= 'doc.type.name'
|
||
and source.type ~= 'doc.class.name'
|
||
and source.type ~= 'doc.enum.name'
|
||
and source.type ~= 'doc.extends.name'
|
||
and source.type ~= 'doc.see.name'
|
||
and source.type ~= 'doc.alias.name' then
|
||
goto CONTINUE
|
||
end
|
||
end
|
||
if src.type == 'doc.generic.name' then
|
||
goto CONTINUE
|
||
end
|
||
if src.type == 'doc.param' then
|
||
goto CONTINUE
|
||
end
|
||
|
||
results[#results+1] = {
|
||
target = src,
|
||
uri = root.uri,
|
||
source = source,
|
||
}
|
||
::CONTINUE::
|
||
end
|
||
|
||
if #results == 0 then
|
||
return nil
|
||
end
|
||
|
||
sortResults(results)
|
||
jumpSource(results)
|
||
|
||
return results
|
||
end
|