diff options
Diffstat (limited to 'script/core/completion')
-rw-r--r-- | script/core/completion/completion.lua | 122 | ||||
-rw-r--r-- | script/core/completion/keyword.lua | 35 |
2 files changed, 133 insertions, 24 deletions
diff --git a/script/core/completion/completion.lua b/script/core/completion/completion.lua index 0ec503de..acb3adbe 100644 --- a/script/core/completion/completion.lua +++ b/script/core/completion/completion.lua @@ -504,7 +504,8 @@ local function checkFieldThen(state, name, src, word, startPos, position, parent local kind = define.CompletionItemKind.Field if (value.type == 'function' and not vm.isVarargFunctionWithOverloads(value)) or value.type == 'doc.type.function' then - if oop then + local isMethod = value.parent.type == 'setmethod' + if isMethod then kind = define.CompletionItemKind.Method else kind = define.CompletionItemKind.Function @@ -512,6 +513,7 @@ local function checkFieldThen(state, name, src, word, startPos, position, parent buildFunction(results, src, value, oop, { label = name, kind = kind, + isMethod = isMethod, match = name:match '^[^(]+', insertText = name:match '^[^(]+', deprecated = vm.getDeprecated(src) and true or nil, @@ -626,12 +628,43 @@ local function checkFieldOfRefs(refs, state, word, startPos, position, parent, o end ::CONTINUE:: end + + local fieldResults = {} for name, src in util.sortPairs(fields) do if src then - checkFieldThen(state, name, src, word, startPos, position, parent, oop, results) + checkFieldThen(state, name, src, word, startPos, position, parent, oop, fieldResults) await.delay() end end + + local scoreMap = {} + for i, res in ipairs(fieldResults) do + scoreMap[res] = i + end + table.sort(fieldResults, function (a, b) + local score1 = scoreMap[a] + local score2 = scoreMap[b] + if oop then + if not a.isMethod then + score1 = score1 + 10000 + end + if not b.isMethod then + score2 = score2 + 10000 + end + else + if a.isMethod then + score1 = score1 + 10000 + end + if b.isMethod then + score2 = score2 + 10000 + end + end + return score1 < score2 + end) + + for _, res in ipairs(fieldResults) do + results[#results+1] = res + end end ---@async @@ -1218,6 +1251,46 @@ local function insertDocEnum(state, pos, doc, enums) return enums end +---@param state parser.state +---@param pos integer +---@param doc vm.node.object +---@param enums table[] +---@return table[]? +local function insertDocEnumKey(state, pos, doc, enums) + local tbl = doc.bindSource + if not tbl then + return nil + end + local keyEnums = {} + 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 + enums[#enums+1] = { + label = ('%q'):format(key), + kind = define.CompletionItemKind.EnumMember, + id = stack(field, function (newField) ---@async + return { + detail = buildDetail(newField), + description = buildDesc(newField), + } + end), + } + ::CONTINUE:: + end + end + for _, enum in ipairs(keyEnums) do + enums[#enums+1] = enum + end + return enums +end + local function buildInsertDocFunction(doc) local args = {} for i, arg in ipairs(doc.args) do @@ -1283,7 +1356,11 @@ local function insertEnum(state, pos, src, enums, isInArray, mark) elseif src.type == 'global' and src.cate == 'type' then for _, set in ipairs(src:getSets(state.uri)) do if set.type == 'doc.enum' then - insertDocEnum(state, pos, set, enums) + if vm.docHasAttr(set, 'key') then + insertDocEnumKey(state, pos, set, enums) + else + insertDocEnum(state, pos, set, enums) + end end end end @@ -1539,14 +1616,13 @@ local function checkTableLiteralField(state, position, tbl, fields, results) end end if left then - local hasResult = false + local fieldResults = {} for _, field in ipairs(fields) do local name = guide.getKeyName(field) if name and not mark[name] and matchKey(left, tostring(name)) then - hasResult = true - results[#results+1] = { + local res = { label = guide.getKeyName(field), kind = define.CompletionItemKind.Property, id = stack(field, function (newField) ---@async @@ -1556,9 +1632,20 @@ local function checkTableLiteralField(state, position, tbl, fields, results) } end), } + if field.optional + or vm.compileNode(field):isNullable() then + res.insertText = res.label + res.label = res.label.. '?' + end + fieldResults[#fieldResults+1] = res end end - return hasResult + util.sortByScore(fieldResults, { + function (r) return r.insertText and 0 or 1 end, + util.sortCallbackOfIndex(fieldResults), + }) + util.arrayMerge(results, fieldResults) + return #fieldResults > 0 end end @@ -1571,7 +1658,8 @@ local function tryCallArg(state, position, results) if arg and arg.type == 'function' then return end - local node = vm.compileCallArg({ type = 'dummyarg' }, call, argIndex) + ---@diagnostic disable-next-line: missing-fields + local node = vm.compileCallArg({ type = 'dummyarg', uri = state.uri }, call, argIndex) if not node then return end @@ -2070,7 +2158,7 @@ local function tryluaDocByErr(state, position, err, docState, results) end end -local function buildluaDocOfFunction(func) +local function buildluaDocOfFunction(func, pad) local index = 1 local buf = {} buf[#buf+1] = '${1:comment}' @@ -2094,7 +2182,8 @@ local function buildluaDocOfFunction(func) local funcArg = func.args[n] if funcArg[1] and funcArg.type ~= 'self' then index = index + 1 - buf[#buf+1] = ('---@param %s ${%d:%s}'):format( + buf[#buf+1] = ('---%s@param %s ${%d:%s}'):format( + pad and ' ' or '', funcArg[1], index, arg @@ -2103,7 +2192,8 @@ local function buildluaDocOfFunction(func) end for _, rtn in ipairs(returns) do index = index + 1 - buf[#buf+1] = ('---@return ${%d:%s}'):format( + buf[#buf+1] = ('---%s@return ${%d:%s}'):format( + pad and ' ' or '', index, rtn ) @@ -2112,7 +2202,7 @@ local function buildluaDocOfFunction(func) return insertText end -local function tryluaDocOfFunction(doc, results) +local function tryluaDocOfFunction(doc, results, pad) if not doc.bindSource then return end @@ -2134,7 +2224,7 @@ local function tryluaDocOfFunction(doc, results) end end end - local insertText = buildluaDocOfFunction(func) + local insertText = buildluaDocOfFunction(func, pad) results[#results+1] = { label = '@param;@return', kind = define.CompletionItemKind.Snippet, @@ -2152,9 +2242,9 @@ local function tryLuaDoc(state, position, results) end if doc.type == 'doc.comment' then local line = doc.originalComment.text - -- 尝试 ---$ - if line == '-' then - tryluaDocOfFunction(doc, results) + -- 尝试 '---$' or '--- $' + if line == '-' or line == '- ' then + tryluaDocOfFunction(doc, results, line == '- ') return end -- 尝试 ---@$ diff --git a/script/core/completion/keyword.lua b/script/core/completion/keyword.lua index e6f50242..aa0e2148 100644 --- a/script/core/completion/keyword.lua +++ b/script/core/completion/keyword.lua @@ -3,6 +3,7 @@ local files = require 'files' local guide = require 'parser.guide' local config = require 'config' local util = require 'utility' +local lookback = require 'core.look-backward' local keyWordMap = { { 'do', function(info, results) @@ -372,17 +373,35 @@ end" else newText = '::continue::' end + local additional = {} + + local word = lookback.findWord(info.state.lua, guide.positionToOffset(info.state, info.start) - 1) + if word ~= 'goto' then + additional[#additional+1] = { + start = info.start, + finish = info.start, + newText = 'goto ', + } + end + + local hasContinue = guide.eachSourceType(mostInsideBlock, 'label', function (src) + if src[1] == 'continue' then + return true + end + end) + + if not hasContinue then + additional[#additional+1] = { + start = endPos, + finish = endPos, + newText = newText, + } + end results[#results+1] = { label = 'goto continue ..', kind = define.CompletionItemKind.Snippet, - insertText = "goto continue", - additionalTextEdits = { - { - start = endPos, - finish = endPos, - newText = newText, - } - } + insertText = "continue", + additionalTextEdits = additional, } return true end } |