diff options
Diffstat (limited to 'script/core/hover')
-rw-r--r-- | script/core/hover/args.lua | 16 | ||||
-rw-r--r-- | script/core/hover/description.lua | 218 | ||||
-rw-r--r-- | script/core/hover/init.lua | 30 | ||||
-rw-r--r-- | script/core/hover/label.lua | 19 | ||||
-rw-r--r-- | script/core/hover/name.lua | 13 | ||||
-rw-r--r-- | script/core/hover/return.lua | 53 | ||||
-rw-r--r-- | script/core/hover/table.lua | 18 |
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 |