summaryrefslogtreecommitdiff
path: root/script/core/hover
diff options
context:
space:
mode:
Diffstat (limited to 'script/core/hover')
-rw-r--r--script/core/hover/args.lua16
-rw-r--r--script/core/hover/description.lua218
-rw-r--r--script/core/hover/init.lua30
-rw-r--r--script/core/hover/label.lua19
-rw-r--r--script/core/hover/name.lua13
-rw-r--r--script/core/hover/return.lua53
-rw-r--r--script/core/hover/table.lua18
7 files changed, 232 insertions, 135 deletions
diff --git a/script/core/hover/args.lua b/script/core/hover/args.lua
index c485d9b9..bb4d4297 100644
--- a/script/core/hover/args.lua
+++ b/script/core/hover/args.lua
@@ -9,7 +9,7 @@ local function asFunction(source)
methodDef = true
end
if methodDef then
- args[#args+1] = ('self: %s'):format(vm.getInfer(parent.node):view 'any')
+ args[#args+1] = ('self: %s'):format(vm.getInfer(parent.node):view(guide.getUri(source), 'any'))
end
if source.args then
for i = 1, #source.args do
@@ -29,15 +29,15 @@ local function asFunction(source)
args[#args+1] = ('%s%s: %s'):format(
name,
optional and '?' or '',
- vm.getInfer(argNode):view('any', guide.getUri(source))
+ vm.getInfer(argNode):view(guide.getUri(source), 'any')
)
elseif arg.type == '...' then
- args[#args+1] = ('%s: %s'):format(
+ args[#args+1] = ('%s%s'):format(
'...',
- vm.getInfer(arg):view 'any'
+ vm.getInfer(arg):view(guide.getUri(source), 'any')
)
else
- args[#args+1] = ('%s'):format(vm.getInfer(arg):view 'any')
+ args[#args+1] = ('%s'):format(vm.getInfer(arg):view(guide.getUri(source), 'any'))
end
::CONTINUE::
end
@@ -46,17 +46,17 @@ local function asFunction(source)
end
local function asDocFunction(source)
+ local args = {}
if not source.args then
- return ''
+ return args
end
- local args = {}
for i = 1, #source.args do
local arg = source.args[i]
local name = arg.name[1]
args[i] = ('%s%s: %s'):format(
name,
arg.optional and '?' or '',
- arg.extends and vm.getInfer(arg.extends):view 'any' or 'any'
+ arg.extends and vm.getInfer(arg.extends):view(guide.getUri(source), 'any') or 'any'
)
end
return args
diff --git a/script/core/hover/description.lua b/script/core/hover/description.lua
index e9267c0f..e11dd6c8 100644
--- a/script/core/hover/description.lua
+++ b/script/core/hover/description.lua
@@ -6,11 +6,12 @@ local lang = require 'language'
local util = require 'utility'
local guide = require 'parser.guide'
local rpath = require 'workspace.require-path'
+local furi = require 'file-uri'
local function collectRequire(mode, literal, uri)
local result, searchers
if mode == 'require' then
- result, searchers = rpath.findUrisByRequirePath(uri, literal)
+ result, searchers = rpath.findUrisByRequireName(uri, literal)
elseif mode == 'dofile'
or mode == 'loadfile' then
result = ws.findUrisByFilePath(literal)
@@ -82,7 +83,53 @@ local function asString(source)
or asStringView(source, literal)
end
-local function getBindComment(source, docGroup, base)
+---@param comment string
+---@param suri uri
+---@return string?
+local function normalizeComment(comment, suri)
+ if not comment then
+ return nil
+ end
+ if comment:sub(1, 1) == '-' then
+ comment = comment:sub(2)
+ end
+ if comment:sub(1, 1) == '@' then
+ return nil
+ end
+ comment = comment:gsub('(%[.-%]%()(.-)(%))', function (left, path, right)
+ local scheme = furi.split(path)
+ if scheme
+ -- strange way to check `C:/xxx.lua`
+ and #scheme > 1 then
+ return
+ end
+ local absPath = ws.getAbsolutePath(suri:gsub('/[^/]+$', ''), path)
+ if not absPath then
+ return
+ end
+ local uri = furi.encode(absPath)
+ return left .. uri .. right
+ end)
+ return comment
+end
+
+local function getBindComment(source)
+ local uri = guide.getUri(source)
+ local lines = {}
+ for _, docComment in ipairs(source.bindComments) do
+ lines[#lines+1] = normalizeComment(docComment.comment.text, uri)
+ end
+ if not lines or #lines == 0 then
+ return nil
+ end
+ return table.concat(lines, '\n')
+end
+
+local function lookUpDocComments(source)
+ local docGroup = source.bindDocs
+ if not docGroup then
+ return
+ end
if source.type == 'setlocal'
or source.type == 'getlocal' then
source = source.node
@@ -90,34 +137,23 @@ local function getBindComment(source, docGroup, base)
if source.parent.type == 'funcargs' then
return
end
- local continue
- local lines
+ local uri = guide.getUri(source)
+ local lines = {}
for _, doc in ipairs(docGroup) do
if doc.type == 'doc.comment' then
- if not continue then
- continue = true
- lines = {}
+ lines[#lines+1] = normalizeComment(doc.comment.text, uri)
+ elseif doc.type == 'doc.type' then
+ if doc.comment then
+ lines[#lines+1] = normalizeComment(doc.comment.text, uri)
end
- if doc.comment.text:sub(1, 1) == '-' then
- lines[#lines+1] = doc.comment.text:sub(2)
- else
- lines[#lines+1] = doc.comment.text
- end
- elseif doc == base then
- break
- else
- continue = false
- if doc.type == 'doc.field'
- or doc.type == 'doc.class' then
- lines = nil
+ elseif doc.type == 'doc.class' then
+ for _, docComment in ipairs(doc.bindComments) do
+ lines[#lines+1] = normalizeComment(docComment.comment.text, uri)
end
end
end
if source.comment then
- if not lines then
- lines = {}
- end
- lines[#lines+1] = source.comment.text
+ lines[#lines+1] = normalizeComment(source.comment.text, uri)
end
if not lines or #lines == 0 then
return nil
@@ -128,8 +164,9 @@ end
local function tryDocClassComment(source)
for _, def in ipairs(vm.getDefs(source)) do
if def.type == 'doc.class'
- or def.type == 'doc.alias' then
- local comment = getBindComment(def, def.bindGroup, def)
+ or def.type == 'doc.alias'
+ or def.type == 'doc.enum' then
+ local comment = getBindComment(def)
if comment then
return comment
end
@@ -144,7 +181,7 @@ local function tryDocModule(source)
return collectRequire('require', source.module, guide.getUri(source))
end
-local function buildEnumChunk(docType, name)
+local function buildEnumChunk(docType, name, uri)
if not docType then
return nil
end
@@ -152,10 +189,11 @@ local function buildEnumChunk(docType, name)
local types = {}
local lines = {}
for _, tp in ipairs(vm.getDefs(docType)) do
- types[#types+1] = vm.getInfer(tp):view()
+ types[#types+1] = vm.getInfer(tp):view(guide.getUri(docType))
if tp.type == 'doc.type.string'
or tp.type == 'doc.type.integer'
- or tp.type == 'doc.type.boolean' then
+ or tp.type == 'doc.type.boolean'
+ or tp.type == 'doc.type.code' then
enums[#enums+1] = tp
end
local comment = tryDocClassComment(tp)
@@ -174,7 +212,7 @@ local function buildEnumChunk(docType, name)
(enum.default and '->')
or (enum.additional and '+>')
or ' |',
- vm.viewObject(enum)
+ vm.viewObject(enum, uri)
)
if enum.comment then
local first = true
@@ -198,26 +236,33 @@ local function getBindEnums(source, docGroup)
return
end
+ local uri = guide.getUri(source)
local mark = {}
local chunks = {}
local returnIndex = 0
for _, doc in ipairs(docGroup) do
if doc.type == 'doc.param' then
local name = doc.param[1]
+ if name == '...' then
+ name = '...(param)'
+ end
if mark[name] then
goto CONTINUE
end
mark[name] = true
- chunks[#chunks+1] = buildEnumChunk(doc.extends, name)
+ chunks[#chunks+1] = buildEnumChunk(doc.extends, name, uri)
elseif doc.type == 'doc.return' then
for _, rtn in ipairs(doc.returns) do
returnIndex = returnIndex + 1
local name = rtn.name and rtn.name[1] or ('return #%d'):format(returnIndex)
+ if name == '...' then
+ name = '...(return)'
+ end
if mark[name] then
goto CONTINUE
end
mark[name] = true
- chunks[#chunks+1] = buildEnumChunk(rtn, name)
+ chunks[#chunks+1] = buildEnumChunk(rtn, name, uri)
end
end
::CONTINUE::
@@ -228,37 +273,38 @@ local function getBindEnums(source, docGroup)
return table.concat(chunks, '\n\n')
end
-local function tryDocFieldUpComment(source)
- if source.type ~= 'doc.field.name' then
+local function tryDocFieldComment(source)
+ if source.type ~= 'doc.field' then
return
end
- local docField = source.parent
- if not docField.bindGroup then
- return
+ if source.comment then
+ return normalizeComment(source.comment.text, guide.getUri(source))
+ end
+ if source.bindGroup then
+ return getBindComment(source)
end
- local comment = getBindComment(docField, docField.bindGroup, docField)
- return comment
end
local function getFunctionComment(source)
local docGroup = source.bindDocs
+ if not docGroup then
+ return
+ end
local hasReturnComment = false
- for _, doc in ipairs(docGroup) do
+ for _, doc in ipairs(source.bindDocs) do
if doc.type == 'doc.return' and doc.comment then
hasReturnComment = true
break
end
end
+ local uri = guide.getUri(source)
local md = markdown()
for _, doc in ipairs(docGroup) do
if doc.type == 'doc.comment' then
- if doc.comment.text:sub(1, 1) == '-' then
- md:add('md', doc.comment.text:sub(2))
- else
- md:add('md', doc.comment.text)
- end
+ local comment = normalizeComment(doc.comment.text, uri)
+ md:add('md', comment)
elseif doc.type == 'doc.param' then
if doc.comment then
md:add('md', ('@*param* `%s` — %s'):format(
@@ -295,18 +341,36 @@ local function getFunctionComment(source)
local enums = getBindEnums(source, docGroup)
md:add('lua', enums)
- return md
+
+ local comment = md:string()
+ if comment == '' then
+ return nil
+ end
+ return comment
end
local function tryDocComment(source)
- if not source.bindDocs then
- return
+ local md = markdown()
+ if source.type == 'function' then
+ local comment = getFunctionComment(source)
+ md:add('md', comment)
+ source = source.parent
end
- if source.type ~= 'function' then
- local comment = getBindComment(source, source.bindDocs)
- return comment
+ local comment = lookUpDocComments(source)
+ md:add('md', comment)
+ if source.type == 'doc.alias' then
+ local enums = buildEnumChunk(source, source.alias[1], guide.getUri(source))
+ md:add('lua', enums)
end
- return getFunctionComment(source)
+ if source.type == 'doc.enum' then
+ local enums = buildEnumChunk(source, source.enum[1], guide.getUri(source))
+ md:add('lua', enums)
+ end
+ local result = md:string()
+ if result == '' then
+ return nil
+ end
+ return result
end
local function tryDocOverloadToComment(source)
@@ -315,14 +379,12 @@ local function tryDocOverloadToComment(source)
end
local doc = source.parent
if doc.type ~= 'doc.overload'
- or not doc.bindSources then
+ or not doc.bindSource then
return
end
- for _, src in ipairs(doc.bindSources) do
- local md = tryDocComment(src)
- if md then
- return md
- end
+ local md = tryDocComment(doc.bindSource)
+ if md then
+ return md
end
end
@@ -350,6 +412,45 @@ local function tyrDocParamComment(source)
end
end
+---@param source parser.object
+local function tryDocEnum(source)
+ if source.type ~= 'doc.enum' then
+ return
+ end
+ local tbl = source.bindSource
+ if not tbl then
+ return
+ end
+ local md = markdown()
+ md:add('lua', '{')
+ for _, field in ipairs(tbl) do
+ if field.type == 'tablefield'
+ or field.type == 'tableindex' then
+ if not field.value then
+ goto CONTINUE
+ end
+ local key = guide.getKeyName(field)
+ if not key then
+ goto CONTINUE
+ end
+ if field.value.type == 'integer'
+ or field.value.type == 'string' then
+ md:add('lua', (' %s: %s = %s,'):format(key, field.value.type, field.value[1]))
+ end
+ if field.value.type == 'binary'
+ or field.value.type == 'unary' then
+ local number = vm.getNumber(field.value)
+ if number then
+ md:add('lua', (' %s: %s = %s,'):format(key, math.tointeger(number) and 'integer' or 'number', number))
+ end
+ end
+ ::CONTINUE::
+ end
+ end
+ md:add('lua', '}')
+ return md:string()
+end
+
return function (source)
if source.type == 'string' then
return asString(source)
@@ -358,9 +459,10 @@ return function (source)
source = source.parent
end
return tryDocOverloadToComment(source)
- or tryDocFieldUpComment(source)
+ or tryDocFieldComment(source)
or tyrDocParamComment(source)
or tryDocComment(source)
or tryDocClassComment(source)
or tryDocModule(source)
+ or tryDocEnum(source)
end
diff --git a/script/core/hover/init.lua b/script/core/hover/init.lua
index 7231944a..5a65cbce 100644
--- a/script/core/hover/init.lua
+++ b/script/core/hover/init.lua
@@ -39,7 +39,7 @@ local function getHover(source)
end
local oop
- if vm.getInfer(source):view() == 'function' then
+ if vm.getInfer(source):view(guide.getUri(source)) == 'function' then
local defs = vm.getDefs(source)
-- make sure `function` is before `doc.type.function`
local orders = {}
@@ -92,19 +92,21 @@ local function getHover(source)
end
local accept = {
- ['local'] = true,
- ['setlocal'] = true,
- ['getlocal'] = true,
- ['setglobal'] = true,
- ['getglobal'] = true,
- ['field'] = true,
- ['method'] = true,
- ['string'] = true,
- ['number'] = true,
- ['integer'] = true,
- ['doc.type.name'] = true,
- ['function'] = true,
- ['doc.module'] = true,
+ ['local'] = true,
+ ['setlocal'] = true,
+ ['getlocal'] = true,
+ ['setglobal'] = true,
+ ['getglobal'] = true,
+ ['field'] = true,
+ ['method'] = true,
+ ['string'] = true,
+ ['number'] = true,
+ ['integer'] = true,
+ ['doc.type.name'] = true,
+ ['doc.class.name'] = true,
+ ['doc.enum.name'] = true,
+ ['function'] = true,
+ ['doc.module'] = true,
}
---@async
diff --git a/script/core/hover/label.lua b/script/core/hover/label.lua
index 2bbfe806..5c502ec1 100644
--- a/script/core/hover/label.lua
+++ b/script/core/hover/label.lua
@@ -33,7 +33,10 @@ local function asDocTypeName(source)
return '(class) ' .. doc.class[1]
end
if doc.type == 'doc.alias' then
- return '(alias) ' .. doc.alias[1] .. ' ' .. lang.script('HOVER_EXTENDS', vm.getInfer(doc.extends):view())
+ return '(alias) ' .. doc.alias[1] .. ' ' .. lang.script('HOVER_EXTENDS', vm.getInfer(doc.extends):view(guide.getUri(source)))
+ end
+ if doc.type == 'doc.enum' then
+ return '(enum) ' .. doc.enum[1]
end
end
end
@@ -42,7 +45,7 @@ end
local function asValue(source, title)
local name = buildName(source, false) or ''
local ifr = vm.getInfer(source)
- local type = ifr:view()
+ local type = ifr:view(guide.getUri(source))
local literal = ifr:viewLiterals()
local cont = buildTable(source)
local pack = {}
@@ -55,10 +58,11 @@ local function asValue(source, title)
and ( type == 'table'
or type == 'any'
or type == 'unknown'
- or type == 'nil') then
- type = nil
+ or type == 'nil'
+ or type:sub(1, 1) == '{') then
+ else
+ pack[#pack+1] = type
end
- pack[#pack+1] = type
if literal then
pack[#pack+1] = '='
pack[#pack+1] = literal
@@ -139,7 +143,7 @@ local function asDocFieldName(source)
break
end
end
- local view = vm.getInfer(source.extends):view()
+ local view = vm.getInfer(source.extends):view(guide.getUri(source))
if not class then
return ('(field) ?.%s: %s'):format(name, view)
end
@@ -212,7 +216,8 @@ return function (source, oop)
elseif source.type == 'number'
or source.type == 'integer' then
return asNumber(source)
- elseif source.type == 'doc.type.name' then
+ elseif source.type == 'doc.type.name'
+ or source.type == 'doc.enum.name' then
return asDocTypeName(source)
elseif source.type == 'doc.field' then
return asDocFieldName(source)
diff --git a/script/core/hover/name.lua b/script/core/hover/name.lua
index f8473638..3fabfb89 100644
--- a/script/core/hover/name.lua
+++ b/script/core/hover/name.lua
@@ -20,6 +20,9 @@ local function asField(source, oop)
local class
if source.node.type ~= 'getglobal' then
class = vm.getInfer(source.node):viewClass()
+ if class == 'any' or class == 'unknown' then
+ class = nil
+ end
end
local node = class
or buildName(source.node, false)
@@ -47,14 +50,12 @@ end
local function asDocFunction(source, oop)
local doc = guide.getParentType(source, 'doc.type')
or guide.getParentType(source, 'doc.overload')
- if not doc or not doc.bindSources then
+ if not doc or not doc.bindSource then
return ''
end
- for _, src in ipairs(doc.bindSources) do
- local name = buildName(src, oop)
- if name ~= '' then
- return name
- end
+ local name = buildName(doc.bindSource, oop)
+ if name ~= '' then
+ return name
end
return ''
end
diff --git a/script/core/hover/return.lua b/script/core/hover/return.lua
index 3d8a94a5..b71b9e5d 100644
--- a/script/core/hover/return.lua
+++ b/script/core/hover/return.lua
@@ -1,34 +1,5 @@
local vm = require 'vm.vm'
-
----@param source parser.object
----@return integer
-local function countReturns(source)
- local n = 0
-
- local docs = source.bindDocs
- if docs then
- for _, doc in ipairs(docs) do
- if doc.type == 'doc.return' then
- for _, rtn in ipairs(doc.returns) do
- if rtn.returnIndex and rtn.returnIndex > n then
- n = rtn.returnIndex
- end
- end
- end
- end
- end
-
- local returns = source.returns
- if returns then
- for _, rtn in ipairs(returns) do
- if #rtn > n then
- n = #rtn
- end
- end
- end
-
- return n
-end
+local guide = require 'parser.guide'
---@param source parser.object
---@return parser.object[]
@@ -50,7 +21,7 @@ local function getReturnDocs(source)
end
local function asFunction(source)
- local num = countReturns(source)
+ local _, _, num = vm.countReturnsOfFunction(source)
if num == 0 then
return nil
end
@@ -62,11 +33,14 @@ local function asFunction(source)
for i = 1, num do
local rtn = vm.getReturnOfFunction(source, i)
local doc = docs[i]
- local name = doc and doc.name and doc.name[1] and (doc.name[1] .. ': ')
- local text = ('%s%s'):format(
+ local name = doc and doc.name and doc.name[1]
+ if name and name ~= '...' then
+ name = name .. ': '
+ end
+ local text = rtn and ('%s%s'):format(
name or '',
- vm.getInfer(rtn):view()
- )
+ vm.getInfer(rtn):view(guide.getUri(source))
+ ) or 'unknown'
if i == 1 then
returns[i] = (' -> %s'):format(text)
else
@@ -83,7 +57,14 @@ local function asDocFunction(source)
end
local returns = {}
for i, rtn in ipairs(source.returns) do
- local rtnText = vm.getInfer(rtn):view()
+ local rtnText = vm.getInfer(rtn):view(guide.getUri(source))
+ if rtn.name then
+ if rtn.name[1] == '...' then
+ rtnText = rtn.name[1] .. rtnText
+ else
+ rtnText = rtn.name[1] .. ': ' .. rtnText
+ end
+ end
if i == 1 then
returns[#returns+1] = (' -> %s'):format(rtnText)
else
diff --git a/script/core/hover/table.lua b/script/core/hover/table.lua
index 16874101..677fd76c 100644
--- a/script/core/hover/table.lua
+++ b/script/core/hover/table.lua
@@ -30,7 +30,7 @@ local function buildAsHash(uri, keys, nodeMap, reachMax)
node:removeOptional()
end
local ifr = vm.getInfer(node)
- local typeView = ifr:view('unknown', uri)
+ local typeView = ifr:view(uri, 'unknown')
local literalView = ifr:viewLiterals()
if literalView then
lines[#lines+1] = (' %s%s: %s = %s,'):format(
@@ -75,7 +75,7 @@ local function buildAsConst(uri, keys, nodeMap, reachMax)
node = node:copy()
node:removeOptional()
end
- local typeView = vm.getInfer(node):view('unknown', uri)
+ local typeView = vm.getInfer(node):view(uri, 'unknown')
local literalView = literalMap[key]
if literalView then
lines[#lines+1] = (' %s%s: %s = %s,'):format(
@@ -154,7 +154,7 @@ local function getNodeMap(fields, keyMap)
local nodeMap = {}
for _, field in ipairs(fields) do
local key = vm.getKeyName(field)
- if not keyMap[key] then
+ if not key or not keyMap[key] then
goto CONTINUE
end
await.delay()
@@ -178,9 +178,15 @@ return function (source)
return nil
end
- for view in vm.getInfer(source):eachView() do
- if view == 'string'
- or vm.isSubType(uri, view, 'string') then
+ local node = vm.compileNode(source)
+ for n in node:eachObject() do
+ if n.type == 'global' and n.cate == 'type' then
+ if n.name == 'string'
+ or (n.name ~= 'unknown' and n.name ~= 'any' and vm.isSubType(uri, n.name, 'string')) then
+ return nil
+ end
+ elseif n.type == 'doc.type.string'
+ or n.type == 'string' then
return nil
end
end