summaryrefslogtreecommitdiff
path: root/server/src/matcher/completion.lua
diff options
context:
space:
mode:
Diffstat (limited to 'server/src/matcher/completion.lua')
-rw-r--r--server/src/matcher/completion.lua121
1 files changed, 121 insertions, 0 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