diff options
-rw-r--r-- | server/src/matcher/completion.lua | 121 | ||||
-rw-r--r-- | server/src/matcher/diagnostics.lua | 6 | ||||
-rw-r--r-- | server/src/matcher/vm.lua | 43 | ||||
-rw-r--r-- | server/src/method/textDocument/completion.lua | 50 | ||||
-rw-r--r-- | server/src/service.lua | 4 | ||||
-rw-r--r-- | server/test/completion/init.lua | 72 |
6 files changed, 228 insertions, 68 deletions
diff --git a/server/src/matcher/completion.lua b/server/src/matcher/completion.lua index 66b993a4..910173f0 100644 --- a/server/src/matcher/completion.lua +++ b/server/src/matcher/completion.lua @@ -1,8 +1,129 @@ local findResult = require 'matcher.find_result' +local CompletionItemKind = { + Text = 1, + Method = 2, + Function = 3, + Constructor = 4, + Field = 5, + Variable = 6, + Class = 7, + Interface = 8, + Module = 9, + Property = 10, + Unit = 11, + Value = 12, + Enum = 13, + Keyword = 14, + Snippet = 15, + Color = 16, + File = 17, + Reference = 18, + Folder = 19, + EnumMember = 20, + Constant = 21, + Struct = 22, + Event = 23, + Operator = 24, + TypeParameter = 25, +} + +local function matchKey(me, other) + if me == other then + return false + end + if #me > #other then + return false + end + local lMe = me:lower() + local lOther = other:lower() + if lMe:sub(1, 1) ~= lOther:sub(1, 1) then + return false + end + if lMe == lOther:sub(1, #lMe) then + return true + end + local used = { + [1] = true, + } + local cur = 2 + local lookup + local researched + for i = 2, #lMe do + local c = lMe:sub(i, i) + -- 1. 看当前字符是否匹配 + if c == lOther:sub(cur, cur) then + used[cur] = true + goto NEXT + end + -- 2. 看前一个字符是否匹配 + if not used[cur-1] then + if c == lOther:sub(cur-1, cur-1) then + used[cur-1] = true + goto NEXT + end + end + -- 3. 向后找这个字 + lookup = lOther:find(c, cur+1, true) + if lookup then + cur = lookup + used[cur] = true + goto NEXT + end + + -- 4. 重新搜索整个字符串,但是只允许1次,否则失败.如果找不到也失败 + if researched then + return false + else + researched = true + for j = 2, cur - 2 do + if c == lOther:sub(j, j) then + used[j] = true + goto NEXT + end + end + return false + end + -- 5. 找到下一个可用的字,如果超出长度则失败 + ::NEXT:: + repeat + cur = cur + 1 + until not used[cur] + if cur > #lOther then + return false + end + end + return true +end + +local function searchLocals(vm, pos, name, callback) + for _, loc in ipairs(vm.results.locals) do + if loc.source.start == 0 then + goto CONTINUE + end + if loc.source.start <= pos and loc.close >= pos then + if matchKey(name, loc.key) then + callback(loc.key) + end + end + ::CONTINUE:: + end +end + return function (vm, pos) local result = findResult(vm, pos) if not result then return nil end + local list = {} + local source = result.source + if source.type == 'name' then + searchLocals(vm, pos, result.key, function (label) + list[#list+1] = { + label = label, + kind = CompletionItemKind.Variable, + } + end) + end + return list end diff --git a/server/src/matcher/diagnostics.lua b/server/src/matcher/diagnostics.lua index 7a190354..f22ce7cb 100644 --- a/server/src/matcher/diagnostics.lua +++ b/server/src/matcher/diagnostics.lua @@ -150,7 +150,11 @@ local function searchRedundantParameters(results, callback) local passed = #call.args for i = max + 1, passed do local source = call.args[i] - callback(source.start, source.finish, max, passed) + if source.start then + callback(source.start, source.finish, max, passed) + else + log.error('No start: ', table.dump(source)) + end end ::NEXT_CALL:: end diff --git a/server/src/matcher/vm.lua b/server/src/matcher/vm.lua index e1da6a81..83c29555 100644 --- a/server/src/matcher/vm.lua +++ b/server/src/matcher/vm.lua @@ -11,10 +11,12 @@ function mt:createLocal(key, source, value) type = 'local', key = key, source = source or DefaultSource, + close = self.scope.block.finish, } local shadow = self.scope.locals[key] if shadow then + shadow.close = source and (source.start-1) local group if shadow.shadow then group = shadow.shadow @@ -34,6 +36,18 @@ function mt:createLocal(key, source, value) return loc end +function mt:scopePush(block) + if not block.start then + error('Scope push without start!') + end + self.scope:push() + self.scope.block = block +end + +function mt:scopePop() + self.scope:pop() +end + function mt:addInfo(obj, type, source) if source and not source.start then error('Miss start: ' .. table.dump(source)) @@ -255,7 +269,7 @@ function mt:buildFunction(exp, object) func.built = true - self.scope:push() + self:scopePush(exp) self.chunk:push() self.chunk:cut 'dots' self.chunk:cut 'labels' @@ -291,7 +305,7 @@ function mt:buildFunction(exp, object) self.results.funcs[#self.results.funcs+1] = func self.chunk:pop() - self.scope:pop() + self:scopePop() return func end @@ -889,9 +903,9 @@ function mt:getExp(exp) end function mt:doDo(action) - self.scope:push() + self:scopePush(action) self:doActions(action) - self.scope:pop() + self:scopePop() end function mt:doReturn(action) @@ -961,9 +975,9 @@ function mt:doIf(action) self:getExp(block.filter) end - self.scope:push() + self:scopePush(block) self:doActions(block) - self.scope:pop() + self:scopePop() end end @@ -975,16 +989,16 @@ function mt:doLoop(action) self:getExp(action.step) end - self.scope:push() + self:scopePush(action) self:createLocal(action.arg[1], action.arg, min) self:doActions(action) - self.scope:pop() + self:scopePop() end function mt:doIn(action) local args = self:unpackList(action.exp) - self.scope:push() + self:scopePush(action) local func = table.remove(args, 1) or self:createValue('any') local values = self:call(func, args) self:forList(action.arg, function (arg) @@ -994,23 +1008,23 @@ function mt:doIn(action) self:doActions(action) - self.scope:pop() + self:scopePop() end function mt:doWhile(action) self:getExp(action.filter) - self.scope:push() + self:scopePush(action) self:doActions(action) - self.scope:pop() + self:scopePop() end function mt:doRepeat(action) - self.scope:push() + self:scopePush(action) self:doActions(action) self:getExp(action.filter) - self.scope:pop() + self:scopePop() end function mt:doFunction(action) @@ -1081,6 +1095,7 @@ function mt:doActions(actions) end function mt:createEnvironment() + self.scope.block = { start = 0, finish = math.maxinteger } -- 整个文件是一个函数 self.chunk.func = self:buildFunction() self.results.main = self.chunk.func diff --git a/server/src/method/textDocument/completion.lua b/server/src/method/textDocument/completion.lua index 9b040f17..2e03882e 100644 --- a/server/src/method/textDocument/completion.lua +++ b/server/src/method/textDocument/completion.lua @@ -1,29 +1,29 @@ local CompletionItemKind = { - Text = 1, - Method = 2, - Function = 3, - Constructor = 4, - Field = 5, - Variable = 6, - Class = 7, - Interface = 8, - Module = 9, - Property = 10, - Unit = 11, - Value = 12, - Enum = 13, - Keyword = 14, - Snippet = 15, - Color = 16, - File = 17, - Reference = 18, - Folder = 19, - EnumMember = 20, - Constant = 21, - Struct = 22, - Event = 23, - Operator = 24, - TypeParameter = 25, + Text = 1, + Method = 2, + Function = 3, + Constructor = 4, + Field = 5, + Variable = 6, + Class = 7, + Interface = 8, + Module = 9, + Property = 10, + Unit = 11, + Value = 12, + Enum = 13, + Keyword = 14, + Snippet = 15, + Color = 16, + File = 17, + Reference = 18, + Folder = 19, + EnumMember = 20, + Constant = 21, + Struct = 22, + Event = 23, + Operator = 24, + TypeParameter = 25, } return function (lsp, params) diff --git a/server/src/service.lua b/server/src/service.lua index 62131446..f7c81317 100644 --- a/server/src/service.lua +++ b/server/src/service.lua @@ -41,8 +41,10 @@ function mt:_callMethod(name, params) if suc then return res else + local suc, res = pcall(table.dump, params) + local dump = suc and res or 'Cyclic table' log.debug(('Task [%s] failed, params: %s'):format( - name, table.dump(params) + name, dump )) return nil, { code = ErrorCodes.InternalError, diff --git a/server/test/completion/init.lua b/server/test/completion/init.lua index 684a8fe7..da633a86 100644 --- a/server/test/completion/init.lua +++ b/server/test/completion/init.lua @@ -2,31 +2,31 @@ local matcher = require 'matcher' local parser = require 'parser' local CompletionItemKind = { - Text = 1, - Method = 2, - Function = 3, - Constructor = 4, - Field = 5, - Variable = 6, - Class = 7, - Interface = 8, - Module = 9, - Property = 10, - Unit = 11, - Value = 12, - Enum = 13, - Keyword = 14, - Snippet = 15, - Color = 16, - File = 17, - Reference = 18, - Folder = 19, - EnumMember = 20, - Constant = 21, - Struct = 22, - Event = 23, - Operator = 24, - TypeParameter = 25, + Text = 1, + Method = 2, + Function = 3, + Constructor = 4, + Field = 5, + Variable = 6, + Class = 7, + Interface = 8, + Module = 9, + Property = 10, + Unit = 11, + Value = 12, + Enum = 13, + Keyword = 14, + Snippet = 15, + Color = 16, + File = 17, + Reference = 18, + Folder = 19, + EnumMember = 20, + Constant = 21, + Struct = 22, + Event = 23, + Operator = 24, + TypeParameter = 25, } local function eq(a, b) @@ -79,7 +79,25 @@ a@ } TEST [[ +local abcdefg local abcde -abcde +abcde@ ]] -{} +{ + { + label = 'abcdefg', + kind = CompletionItemKind.Variable, + } +} + +TEST [[ +local abcdefg +a@ +local abcde +]] +{ + { + label = 'abcdefg', + kind = CompletionItemKind.Variable, + } +} |