diff options
author | sumneko <sumneko@hotmail.com> | 2019-04-25 21:01:20 +0800 |
---|---|---|
committer | sumneko <sumneko@hotmail.com> | 2019-04-25 21:01:20 +0800 |
commit | d467b51cf4ce3b405fe131ddd75a6844e17797f3 (patch) | |
tree | be33a3067862e7da605c3f9cafddc9e39f7ab787 /server | |
parent | 3391ab935f18e928da414c19a84e7afc4acee779 (diff) | |
download | lua-language-server-d467b51cf4ce3b405fe131ddd75a6844e17797f3.zip |
参数自动完成
Diffstat (limited to 'server')
-rw-r--r-- | server/main.lua | 2 | ||||
-rw-r--r-- | server/src/core/completion.lua | 73 | ||||
-rw-r--r-- | server/src/parser/ast.lua | 43 | ||||
-rw-r--r-- | server/src/parser/grammar.lua | 12 | ||||
-rw-r--r-- | server/test/completion/init.lua | 46 |
5 files changed, 133 insertions, 43 deletions
diff --git a/server/main.lua b/server/main.lua index ac7860c5..685fce01 100644 --- a/server/main.lua +++ b/server/main.lua @@ -22,7 +22,7 @@ local function tryDebugger() log.info('Debugger startup, listen port: 11411') end ---pcall(tryDebugger) +pcall(tryDebugger) require 'utility' require 'global_protect' diff --git a/server/src/core/completion.lua b/server/src/core/completion.lua index 1ae88c8f..3daf71d5 100644 --- a/server/src/core/completion.lua +++ b/server/src/core/completion.lua @@ -304,18 +304,11 @@ local function searchIndex(vm, source, word, callback) end) end -local function searchCloseGlobal(vm, source, word, callback) - local loc = source:bindLocal() - if not loc then - return - end - local close = loc:close() - -- 因为闭包的关系落在局部变量finish到close范围内的全局变量一定能访问到该局部变量 - +local function searchCloseGlobal(vm, start, finish, word, callback) vm:eachSource(function (src) if (src:get 'global' or src:bindLocal()) - and src.start >= source.finish - and src.finish <= close + and src.start >= start + and src.finish <= finish then if matchKey(word, src[1]) then callback(src[1], src, CompletionItemKind.Variable) @@ -324,13 +317,26 @@ local function searchCloseGlobal(vm, source, word, callback) end) end -local function searchParams(vm, source, word, callback) +local function searchParams(vm, source, func, word, callback) ---@type function - local func = source:get 'arg' local emmyParams = func:getEmmyParams() if not emmyParams then return end + if #emmyParams > 1 then + if not func.args + or not func.args[1] + or func.args[1]:getSource() == source then + if matchKey(word, source and source[1] or '') then + local names = {} + for _, param in ipairs(emmyParams) do + local name = param:getName() + names[#names+1] = name + end + callback(table.concat(names, ', '), nil, CompletionItemKind.Snippet) + end + end + end for _, param in ipairs(emmyParams) do local name = param:getName() if matchKey(word, name) then @@ -390,7 +396,12 @@ local function searchAsIndex(vm, source, word, callback) end local function searchAsLocal(vm, source, word, callback) - searchCloseGlobal(vm, source, word, callback) + local loc = source:bindLocal() + if loc then + local close = loc:close() + -- 因为闭包的关系落在局部变量finish到close范围内的全局变量一定能访问到该局部变量 + searchCloseGlobal(vm, source.finish, close, word, callback) + end -- 特殊支持 local function if matchKey(word, 'function') then callback('function', nil, CompletionItemKind.Keyword) @@ -402,8 +413,22 @@ local function searchAsLocal(vm, source, word, callback) end local function searchAsArg(vm, source, word, callback) - searchParams(vm, source, word, callback) - searchCloseGlobal(vm, source, word, callback) + searchParams(vm, source, source:get 'arg', word, callback) + + local loc = source:bindLocal() + if loc then + local close = loc:close() + -- 因为闭包的关系落在局部变量finish到close范围内的全局变量一定能访问到该局部变量 + searchCloseGlobal(vm, source.finish, close, word, callback) + return + end +end + +local function searchFunction(vm, source, word, pos, callback) + if pos >= source.argStart and pos <= source.argFinish then + searchParams(vm, nil, source:bindFunction():getFunction(), word, callback) + searchCloseGlobal(vm, source.argFinish, source.finish, word, callback) + end end local function searchEmmyKeyword(vm, source, word, callback) @@ -436,7 +461,7 @@ local function searchEmmyFunctionParam(vm, source, word, callback) if not func.args then return end - if word == '' then + if #func.args > 1 and matchKey(word, func.args[1].name) then local list = {} local args = {} for i, arg in ipairs(func.args) do @@ -447,18 +472,18 @@ local function searchEmmyFunctionParam(vm, source, word, callback) list[i] = ('---@param %s any'):format(arg.name) end end - callback(('(%s)'):format(table.concat(args, ', ')), nil, CompletionItemKind.Snippet, { + callback(('%s'):format(table.concat(args, ', ')), nil, CompletionItemKind.Snippet, { insertText = table.concat(list, '\n') }) end for _, arg in ipairs(func.args) do if matchKey(word, arg.name) then - callback(arg.name, arg, CompletionItemKind.Interface) + callback(arg.name, nil, CompletionItemKind.Interface) end end end -local function searchSource(vm, source, word, callback) +local function searchSource(vm, source, word, callback, pos) if source.type == 'keyword' then searchAsKeyowrd(vm, source, word, callback) return @@ -487,6 +512,10 @@ local function searchSource(vm, source, word, callback) searchAsSuffix(vm, source, word, callback) return end + if source:bindFunction() then + searchFunction(vm, source, word, pos, callback) + return + end if source.type == 'emmyIncomplete' then searchEmmyKeyword(vm, source, word, callback) State.ignoreText = true @@ -758,7 +787,7 @@ local function findStartPos(pos, buf) if not res then for i = pos, 1, -1 do local c = buf:sub(i, i) - if c == '.' or c == ':' or c == '|' then + if c == '.' or c == ':' or c == '|' or c == '(' then res = i break elseif c == '#' or c == '@' then @@ -809,6 +838,8 @@ return function (vm, text, pos, oldText) ['emmyName'] = true, ['emmyIncomplete'] = true, ['call'] = true, + ['function'] = true, + ['localfunction'] = true, } local source, pos, word = getSource(vm, pos, text, filter) if not source then @@ -827,7 +858,7 @@ return function (vm, text, pos, oldText) end searchSpecial(vm, source, word, callback, pos, text) searchCallArg(vm, source, word, callback, pos) - searchSource(vm, source, word, callback) + searchSource(vm, source, word, callback, pos) if not oldText or #list > 0 then if not State.ignoreText then searchAllWords(vm, source, word, callback, pos) diff --git a/server/src/parser/ast.lua b/server/src/parser/ast.lua index 7df7676d..f93870e4 100644 --- a/server/src/parser/ast.lua +++ b/server/src/parser/ast.lua @@ -559,42 +559,57 @@ local Defs = { finish = start, } end, - Function = function (start, arg, ...) + Function = function (start, argStart, arg, argFinish, ...) local obj = { - type = 'function', - start = start, - arg = arg, + type = 'function', + start = start, + arg = arg, + argStart = argStart - 1, + argFinish = argFinish, ... } local max = #obj obj.finish = obj[max] - 1 obj[max] = nil + if obj.argFinish > obj.finish then + obj.argFinish = obj.finish + end return obj end, - NamedFunction = function (start, name, arg, ...) + NamedFunction = function (start, name, argStart, arg, argFinish, ...) local obj = { - type = 'function', - start = start, - name = name, - arg = arg, + type = 'function', + start = start, + name = name, + arg = arg, + argStart = argStart - 1, + argFinish = argFinish, ... } local max = #obj obj.finish = obj[max] - 1 obj[max] = nil + if obj.argFinish > obj.finish then + obj.argFinish = obj.finish + end return obj end, - LocalFunction = function (start, name, arg, ...) + LocalFunction = function (start, name, argStart, arg, argFinish, ...) local obj = { - type = 'localfunction', - start = start, - name = name, - arg = arg, + type = 'localfunction', + start = start, + name = name, + arg = arg, + argStart = argStart - 1, + argFinish = argFinish, ... } local max = #obj obj.finish = obj[max] - 1 obj[max] = nil + if obj.argFinish > obj.finish then + obj.argFinish = obj.finish + end return obj end, Table = function (start, ...) diff --git a/server/src/parser/grammar.lua b/server/src/parser/grammar.lua index 03e14776..2da20161 100644 --- a/server/src/parser/grammar.lua +++ b/server/src/parser/grammar.lua @@ -353,8 +353,8 @@ NewField <- (MustName ASSIGN DirtyExp) Function <- Sp ({} FunctionBody {}) -> Function -FuncArg <- PL ArgList NeedPR - / {} -> MissPL Nothing +FuncArg <- PL {} ArgList {} NeedPR + / {} {} -> MissPL Nothing {} FunctionBody<- FUNCTION FuncArg LabelStart (!END Action)* @@ -560,10 +560,10 @@ EmmyParam <- MustEmmyName %s* EmmyType EmmyTypeEnums* EmmyReturn <- EmmyType -EmmyField <- (EmmyFieldAccess MustEmmyName %s+ EmmyType) -EmmyFieldAccess <- ({'public'} %s+) - / ({'protected'} %s+) - / ({'private'} %s+) +EmmyField <- (EmmyFieldAccess MustEmmyName %s* EmmyType) +EmmyFieldAccess <- ({'public'} Cut %s*) + / ({'protected'} Cut %s*) + / ({'private'} Cut %s*) / {} -> 'public' EmmyGeneric <- EmmyGenericBlock diff --git a/server/test/completion/init.lua b/server/test/completion/init.lua index 60e197bc..aa310d30 100644 --- a/server/test/completion/init.lua +++ b/server/test/completion/init.lua @@ -850,7 +850,7 @@ end ]] { { - label = '(a, b, c)', + label = 'a, b, c', kind = CompletionItemKind.Snippet, insertText = [[ a any @@ -878,6 +878,50 @@ function f(x$) ]] { { + label = 'xyz, xxx', + kind = CompletionItemKind.Snippet, + }, + { + label = 'xyz', + kind = CompletionItemKind.Interface, + }, + { + label = 'xxx', + kind = CompletionItemKind.Interface, + }, +} + +TEST [[ +---@param xyz Class +---@param xxx Class +function f($ +]] +{ + { + label = 'xyz, xxx', + kind = CompletionItemKind.Snippet, + }, + { + label = 'xyz', + kind = CompletionItemKind.Interface, + }, + { + label = 'xxx', + kind = CompletionItemKind.Interface, + }, +} + +TEST [[ +---@param xyz Class +---@param xxx Class +function f($) +]] +{ + { + label = 'xyz, xxx', + kind = CompletionItemKind.Snippet, + }, + { label = 'xyz', kind = CompletionItemKind.Interface, }, |