diff options
-rw-r--r-- | server/src/core/completion.lua | 73 | ||||
-rw-r--r-- | server/src/core/diagnostics.lua | 2 | ||||
-rw-r--r-- | server/src/vm/function.lua | 14 | ||||
-rw-r--r-- | server/src/vm/value.lua | 8 | ||||
-rw-r--r-- | server/src/vm/vm.lua | 36 | ||||
-rw-r--r-- | server/test/completion/init.lua | 40 |
6 files changed, 143 insertions, 30 deletions
diff --git a/server/src/core/completion.lua b/server/src/core/completion.lua index f2d2dceb..ede33524 100644 --- a/server/src/core/completion.lua +++ b/server/src/core/completion.lua @@ -246,7 +246,7 @@ end local function searchCloseGlobal(vm, source, word, callback) local loc = source:bindLocal() local close = loc:close() - -- 因为闭包的关系落在局部变量finish到close范围内的source一定能访问到该局部变量 + -- 因为闭包的关系落在局部变量finish到close范围内的全局变量一定能访问到该局部变量 for _, src in ipairs(vm.sources) do if src:get 'global' and src.start >= source.finish @@ -296,11 +296,19 @@ local function searchAsLocal(vm, source, word, callback) end end +local function searchAsArg(vm, source, word, callback) + searchCloseGlobal(vm, source, word, callback) +end + local function searchSource(vm, source, word, callback) if source:get 'table index' then searchAsIndex(vm, source, word, callback) return end + if source:get 'arg' then + searchAsArg(vm, source, word, callback) + return + end if source:get 'global' then searchAsGlobal(vm, source, word, callback) return @@ -319,6 +327,68 @@ local function searchSource(vm, source, word, callback) end end +local function searchCallArg(vm, source, word, callback, pos) + local results = {} + for _, src in ipairs(vm.sources) do + if src.type == 'call' + and src.start <= pos + and src.finish >= pos + then + results[#results+1] = src + end + end + if #results == 0 then + return nil + end + -- 可能处于 'func1(func2(' 的嵌套中,将最近的call放到最前面 + table.sort(results, function (a, b) + return a.start > b.start + end) + local call = results[1] + local func, args = call:bindCall() + + local lib = func:getLib() + if not lib then + return + end + + local select = 1 + for i, arg in ipairs(args) do + if arg.start <= pos and arg.finish >= pos then + select = i + break + end + end + + -- 根据参数位置找枚举值 + if lib.args and lib.enums then + local arg = lib.args[select] + local name = arg and arg.name + for _, enum in ipairs(lib.enums) do + if enum.name == name and enum.enum then + if matchKey(word, enum.enum) then + local label, textEdit + if source.type ~= arg.type then + label = ('%q'):format(enum.enum) + end + if source.type ~= 'call' then + textEdit = { + start = source.start, + finish = source.finish, + newText = ('%q'):format(enum.enum), + } + end + callback(enum.enum, nil, CompletionItemKind.EnumMember, { + label = label, + documentation = enum.description, + textEdit = textEdit, + }) + end + end + end + end +end + local function searchAllWords(vm, source, word, callback) if word == '' then return @@ -365,6 +435,7 @@ return function (vm, pos, word) return nil end local callback, list = makeList(source, word) + searchCallArg(vm, source, word, callback, pos) searchSource(vm, source, word, callback) searchAllWords(vm, source, word, callback) diff --git a/server/src/core/diagnostics.lua b/server/src/core/diagnostics.lua index eb4ca403..f052d7d2 100644 --- a/server/src/core/diagnostics.lua +++ b/server/src/core/diagnostics.lua @@ -220,7 +220,7 @@ function mt:searchRedundantParameters(callback) local passed = #args for i = max + 1, passed do local extra = args[i] - callback(extra.source.start, extra.source.finish, max, passed) + callback(extra.start, extra.finish, max, passed) end end) end diff --git a/server/src/vm/function.lua b/server/src/vm/function.lua index d5f67e25..700f1a19 100644 --- a/server/src/vm/function.lua +++ b/server/src/vm/function.lua @@ -138,7 +138,7 @@ function mt:hasRuned() return self._runed > 0 end -function mt:run() +function mt:run(vm) self._runed = self._runed + 1 if not self.source then return @@ -160,7 +160,7 @@ function mt:run() end -- 显性声明的参数 - self:createArgs() + self:createArgs(vm) end function mt:setArgs(values) @@ -172,7 +172,9 @@ function mt:setArgs(values) end end -function mt:createArg(arg, values) +function mt:createArg(vm, arg, values) + vm:instantSource(arg) + arg:set('arg', true) if arg.type == 'name' then local value = table.remove(values, 1) or createValue('nil', arg) local loc = createLocal(arg[1], arg, value) @@ -201,7 +203,7 @@ function mt:hasDots() return self._dots ~= nil end -function mt:createArgs() +function mt:createArgs(vm) if not self.source then return end @@ -215,10 +217,10 @@ function mt:createArgs() end if args.type == 'list' then for _, arg in ipairs(args) do - self:createArg(arg, values) + self:createArg(vm, arg, values) end else - self:createArg(args, values) + self:createArg(vm, args, values) end end diff --git a/server/src/vm/value.lua b/server/src/vm/value.lua index 7513ebd1..d47d6c15 100644 --- a/server/src/vm/value.lua +++ b/server/src/vm/value.lua @@ -13,14 +13,6 @@ local mt = {} mt.__index = mt mt.type = 'value' -function mt:setValue(value) - self._value = value -end - -function mt:getValue() - return self._value -end - function mt:setType(tp, rate) if type(tp) == 'table' then for _, ctp in ipairs(tp) do diff --git a/server/src/vm/vm.lua b/server/src/vm/vm.lua index 0b994011..41015923 100644 --- a/server/src/vm/vm.lua +++ b/server/src/vm/vm.lua @@ -87,7 +87,7 @@ function mt:buildTable(source) end function mt:runFunction(func) - func:run() + func:run(self) if not func.source then return @@ -391,42 +391,49 @@ function mt:getIndex(source) end function mt:unpackList(list) - local res = createMulti() + local values = createMulti() + local exps = createMulti() if not list then - return res + return values end if list.type == 'list' or list.type == 'call' or list.type == 'return' then for i, exp in ipairs(list) do + self:instantSource(exp) + exps:push(exp) if exp.type == '...' then - res:merge(self:loadDots()) + values:merge(self:loadDots()) break end local value = self:getExp(exp) if value.type == 'multi' then if i == #list then value:eachValue(function (_, v) - res:push(v) + values:push(v) end) else - res:push(self:getFirstInMulti(value)) + values:push(self:getFirstInMulti(value)) end else - res:push(value) + values:push(value) end end elseif list.type == '...' then - res:merge(self:loadDots()) + self:instantSource(list) + exps:push(list) + values:merge(self:loadDots()) else + self:instantSource(list) + exps:push(list) local value = self:getExp(list) if value.type == 'multi' then value:eachValue(function (_, v) - res:push(v) + values:push(v) end) else - res:push(value) + values:push(value) end end - return res + return values, exps end function mt:getFirstInMulti(multi) @@ -456,14 +463,15 @@ function mt:getSimple(simple, max) value = self:getFirstInMulti(value) or createValue('nil') if source.type == 'call' then - local args = self:unpackList(source) + local values, args = self:unpackList(source) local func = value if object then - table.insert(args, 1, object) + table.insert(values, 1, object) + table.insert(args, 1, simple[i-1]) end object = nil source:bindCall(func, args) - value = self:call(func, args, source) or createValue('any') + value = self:call(func, values, source) or createValue('any') elseif source.type == 'index' then source:set('parent', value) local child = source[1] diff --git a/server/test/completion/init.lua b/server/test/completion/init.lua index 2dba35bc..55a71b53 100644 --- a/server/test/completion/init.lua +++ b/server/test/completion/init.lua @@ -405,41 +405,81 @@ collectgarbage('@') label = 'collect', kind = CompletionItemKind.EnumMember, documentation = EXISTS, + textEdit = { + start = 16, + finish = 18, + newText = '"collect"', + }, }, { label = 'stop', kind = CompletionItemKind.EnumMember, documentation = EXISTS, + textEdit = { + start = 16, + finish = 18, + newText = '"stop"', + }, }, { label = 'restart', kind = CompletionItemKind.EnumMember, documentation = EXISTS, + textEdit = { + start = 16, + finish = 18, + newText = '"restart"', + }, }, { label = 'count', kind = CompletionItemKind.EnumMember, documentation = EXISTS, + textEdit = { + start = 16, + finish = 18, + newText = '"count"', + }, }, { label = 'step', kind = CompletionItemKind.EnumMember, documentation = EXISTS, + textEdit = { + start = 16, + finish = 18, + newText = '"step"', + }, }, { label = 'setpause', kind = CompletionItemKind.EnumMember, documentation = EXISTS, + textEdit = { + start = 16, + finish = 18, + newText = '"setpause"', + }, }, { label = 'setstepmul', kind = CompletionItemKind.EnumMember, documentation = EXISTS, + textEdit = { + start = 16, + finish = 18, + newText = '"setstepmul"', + }, }, { label = 'isrunning', kind = CompletionItemKind.EnumMember, documentation = EXISTS, + textEdit = { + start = 16, + finish = 18, + newText = '"isrunning"', + }, }, } |