summaryrefslogtreecommitdiff
path: root/script/core/completion
diff options
context:
space:
mode:
Diffstat (limited to 'script/core/completion')
-rw-r--r--script/core/completion/completion.lua122
-rw-r--r--script/core/completion/keyword.lua35
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 }