236 lines
6 KiB
Lua
236 lines
6 KiB
Lua
|
local workspace = require 'workspace'
|
|||
|
local files = require 'files'
|
|||
|
local vm = require 'vm'
|
|||
|
local findSource = require 'core.find-source'
|
|||
|
local guide = require 'parser.guide'
|
|||
|
local rpath = require 'workspace.require-path'
|
|||
|
local jumpSource = require 'core.jump-source'
|
|||
|
local wssymbol = require 'core.workspace-symbol'
|
|||
|
|
|||
|
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,
|
|||
|
['setglobal'] = true,
|
|||
|
['getglobal'] = true,
|
|||
|
['string'] = true,
|
|||
|
['boolean'] = true,
|
|||
|
['number'] = true,
|
|||
|
['integer'] = true,
|
|||
|
['...'] = true,
|
|||
|
|
|||
|
['doc.type.name'] = true,
|
|||
|
['doc.class.name'] = true,
|
|||
|
['doc.extends.name'] = true,
|
|||
|
['doc.alias.name'] = true,
|
|||
|
['doc.see.name'] = true,
|
|||
|
['doc.cast.name'] = true,
|
|||
|
['doc.enum.name'] = true,
|
|||
|
['doc.field.name'] = true,
|
|||
|
}
|
|||
|
|
|||
|
local function checkRequire(source, offset)
|
|||
|
if source.type ~= 'string' then
|
|||
|
return nil
|
|||
|
end
|
|||
|
local callargs = source.parent
|
|||
|
if callargs.type ~= 'callargs' then
|
|||
|
return
|
|||
|
end
|
|||
|
if callargs[1] ~= source then
|
|||
|
return
|
|||
|
end
|
|||
|
local call = callargs.parent
|
|||
|
local func = call.node
|
|||
|
local literal = guide.getLiteral(source)
|
|||
|
local libName = vm.getLibraryName(func)
|
|||
|
if not libName then
|
|||
|
return nil
|
|||
|
end
|
|||
|
if libName == 'require' then
|
|||
|
return rpath.findUrisByRequireName(guide.getUri(source), literal)
|
|||
|
elseif libName == 'dofile'
|
|||
|
or libName == 'loadfile' then
|
|||
|
return workspace.findUrisByFilePath(literal)
|
|||
|
end
|
|||
|
return nil
|
|||
|
end
|
|||
|
|
|||
|
local function convertIndex(source)
|
|||
|
if not source then
|
|||
|
return
|
|||
|
end
|
|||
|
if source.type == 'string'
|
|||
|
or source.type == 'boolean'
|
|||
|
or source.type == 'number'
|
|||
|
or source.type == 'integer' then
|
|||
|
local parent = source.parent
|
|||
|
if not parent then
|
|||
|
return
|
|||
|
end
|
|||
|
if parent.type == 'setindex'
|
|||
|
or parent.type == 'getindex'
|
|||
|
or parent.type == 'tableindex' then
|
|||
|
return parent
|
|||
|
end
|
|||
|
end
|
|||
|
return source
|
|||
|
end
|
|||
|
|
|||
|
---@async
|
|||
|
---@param source parser.object
|
|||
|
---@param results table
|
|||
|
local function checkSee(source, results)
|
|||
|
if source.type ~= 'doc.see.name' then
|
|||
|
return
|
|||
|
end
|
|||
|
local symbols = wssymbol(source[1], guide.getUri(source))
|
|||
|
for _, symbol in ipairs(symbols) do
|
|||
|
if symbol.name == source[1] then
|
|||
|
results[#results+1] = {
|
|||
|
target = symbol.source,
|
|||
|
source = source,
|
|||
|
uri = guide.getUri(symbol.source),
|
|||
|
}
|
|||
|
end
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
---@async
|
|||
|
return function (uri, offset)
|
|||
|
local ast = files.getState(uri)
|
|||
|
if not ast then
|
|||
|
return nil
|
|||
|
end
|
|||
|
|
|||
|
local source = convertIndex(findSource(ast, offset, accept))
|
|||
|
if not source then
|
|||
|
return nil
|
|||
|
end
|
|||
|
|
|||
|
local results = {}
|
|||
|
local uris = checkRequire(source)
|
|||
|
if uris then
|
|||
|
for i, uri in ipairs(uris) do
|
|||
|
results[#results+1] = {
|
|||
|
uri = uri,
|
|||
|
source = source,
|
|||
|
target = {
|
|||
|
start = 0,
|
|||
|
finish = 0,
|
|||
|
uri = uri,
|
|||
|
}
|
|||
|
}
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
checkSee(source, results)
|
|||
|
|
|||
|
local defs = vm.getDefs(source)
|
|||
|
|
|||
|
for _, src in ipairs(defs) do
|
|||
|
if src.type == 'global' then
|
|||
|
goto CONTINUE
|
|||
|
end
|
|||
|
local root = guide.getRoot(src)
|
|||
|
if not root then
|
|||
|
goto CONTINUE
|
|||
|
end
|
|||
|
if src.type == 'self' 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'
|
|||
|
and src.type ~= 'doc.type.function'
|
|||
|
and src.type ~= 'doc.type.table' 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' then
|
|||
|
if source.type ~= 'doc.type.name'
|
|||
|
and source.type ~= 'doc.extends.name'
|
|||
|
and source.type ~= 'doc.see.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
|