summaryrefslogtreecommitdiff
path: root/server
diff options
context:
space:
mode:
authorsumneko <sumneko@hotmail.com>2019-04-25 21:01:20 +0800
committersumneko <sumneko@hotmail.com>2019-04-25 21:01:20 +0800
commitd467b51cf4ce3b405fe131ddd75a6844e17797f3 (patch)
treebe33a3067862e7da605c3f9cafddc9e39f7ab787 /server
parent3391ab935f18e928da414c19a84e7afc4acee779 (diff)
downloadlua-language-server-d467b51cf4ce3b405fe131ddd75a6844e17797f3.zip
参数自动完成
Diffstat (limited to 'server')
-rw-r--r--server/main.lua2
-rw-r--r--server/src/core/completion.lua73
-rw-r--r--server/src/parser/ast.lua43
-rw-r--r--server/src/parser/grammar.lua12
-rw-r--r--server/test/completion/init.lua46
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,
},