summaryrefslogtreecommitdiff
path: root/server/src/core/completion.old.lua
diff options
context:
space:
mode:
Diffstat (limited to 'server/src/core/completion.old.lua')
-rw-r--r--server/src/core/completion.old.lua578
1 files changed, 0 insertions, 578 deletions
diff --git a/server/src/core/completion.old.lua b/server/src/core/completion.old.lua
deleted file mode 100644
index 57e006e9..00000000
--- a/server/src/core/completion.old.lua
+++ /dev/null
@@ -1,578 +0,0 @@
-local findSource = require 'core.find_source'
-local hover = require 'core.hover'
-
-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 true
- end
- if me == '' then
- return true
- 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 = {}
- local cur = 1
- local lookup
- local researched
- for i = 1, #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 = 1, 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 i == #lMe
- 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 not loc.close then
- log.debug('Miss loc close', table.dump(loc))
- end
- if loc.source.start <= pos and loc.close >= pos then
- if matchKey(name, loc.key) then
- callback(loc)
- end
- end
- ::CONTINUE::
- end
-end
-
-local function sortPairs(t)
- local keys = {}
- for k in pairs(t) do
- keys[#keys+1] = k
- end
- table.sort(keys)
- local i = 0
- return function ()
- i = i + 1
- local k = keys[i]
- return k, t[k]
- end
-end
-
-local function searchFields(name, parentValue, source, callback)
- if not parentValue then
- return
- end
- if type(name) ~= 'string' then
- return
- end
- local map = {}
- parentValue:eachField(function (key, field)
- if type(key) ~= 'string' then
- goto CONTINUE
- end
- if source.object and field.value:getType() ~= 'function' then
- goto CONTINUE
- end
- if matchKey(name, key) then
- map[key] = field
- end
- ::CONTINUE::
- end)
- for _, field in sortPairs(map) do
- callback(field)
- end
-end
-
-local KEYS = {'and', 'break', 'do', 'else', 'elseif', 'end', 'false', 'for', 'function', 'goto', 'if', 'in', 'local', 'nil', 'not', 'or', 'repeat', 'return', 'then', 'true', 'until', 'while', 'toclose'}
-local function searchKeyWords(name, callback)
- for _, key in ipairs(KEYS) do
- if matchKey(name, key) then
- callback(key)
- end
- end
-end
-
-local function getKind(var, default)
- local value = var.value
- if default == CompletionItemKind.Variable then
- if value:getType() == 'function' then
- return CompletionItemKind.Function
- end
- end
- if default == CompletionItemKind.Field then
- local tp = type(value:getValue())
- if tp == 'number' or tp == 'integer' or tp == 'string' then
- return CompletionItemKind.Enum
- end
- if value:getType() == 'function' then
- if value.object then
- return CompletionItemKind.Method
- else
- return CompletionItemKind.Function
- end
- end
- end
- return default
-end
-
-local function getDetail(var)
- local tp = type(var.value:getValue())
- if tp == 'boolean' then
- return ('= %q'):format(var.value:getValue())
- elseif tp == 'number' then
- if math.type(var.value:getValue()) == 'integer' then
- return ('= %q'):format(var.value:getValue())
- else
- local str = ('= %.10f'):format(var.value:getValue())
- local dot = str:find('.', 1, true)
- local suffix = str:find('[0]+$', dot+2)
- if suffix then
- return str:sub(1, suffix-1)
- else
- return str
- end
- end
- elseif tp == 'string' then
- return ('= %q'):format(var.value:getValue())
- end
- return nil
-end
-
-local function getDocument(var, source)
- if not source then
- return nil
- end
- if var.value:getType() == 'function' then
- local hvr = hover(var, source)
- if not hvr then
- return nil
- end
- local text = ([[
-```lua
-%s
-```
-%s
-```lua
-%s
-```
-]]):format(hvr.label or '', hvr.description or '', hvr.enum or '')
- return {
- kind = 'markdown',
- value = text,
- }
- end
- return nil
-end
-
-local function searchAsLocal(vm, word, pos, result, source, callback)
- searchFields(word, vm.env, source, function (var)
- callback(var, CompletionItemKind.Variable)
- end)
-
- -- 支持 local function
- if matchKey(word, 'function') then
- callback('function', CompletionItemKind.Keyword)
- end
-end
-
-local function searchAsArg(vm, word, pos, result, source, callback)
- searchFields(word, vm.env, source, function (var)
- if var.value.lib then
- return
- end
- callback(var, CompletionItemKind.Variable)
- end)
-end
-
-local function searchAsGlobal(vm, word, pos, result, source, callback)
- if word == '' or word == nil then
- return
- end
- searchLocals(vm, pos, word, function (var)
- callback(var, CompletionItemKind.Variable)
- end)
- searchFields(word, result.parentValue, source, function (var)
- callback(var, CompletionItemKind.Field)
- end)
- searchKeyWords(word, function (name)
- callback(name, CompletionItemKind.Keyword)
- end)
-end
-
-local function searchAsSuffix(result, source, word, callback)
- searchFields(word, result.parentValue, source, function (var)
- callback(var, CompletionItemKind.Field)
- end)
-end
-
-local function searchInArg(vm, inCall, inString, callback)
- local lib = inCall.func.lib
- if not lib then
- return
- end
-
- -- require列举出可以引用到的文件
- if lib.special == 'require' then
- if not vm.lsp or not vm.lsp.workspace or not inString then
- return
- end
- local results = vm.lsp.workspace:matchPath(vm.uri, inString[1])
- if not results then
- return
- end
- for _, v in ipairs(results) do
- if v ~= inString[1] then
- callback(v, CompletionItemKind.File, {
- textEdit = {
- start = inString.start+1,
- finish = inString.finish-1,
- newText = ('%q'):format(v):sub(2, -2),
- }
- })
- end
- end
- end
-
- -- 其他库函数,根据参数位置找枚举值
- if lib.args and lib.enums then
- local arg = lib.args[inCall.select]
- local name = arg and arg.name
- for _, enum in ipairs(lib.enums) do
- if enum.name == name and enum.enum then
- if inString then
- callback(enum.enum, CompletionItemKind.EnumMember, {
- documentation = enum.description
- })
- else
- callback(('%q'):format(enum.enum), CompletionItemKind.EnumMember, {
- documentation = enum.description
- })
- end
- end
- end
- end
-end
-
-local function searchAsIndex(vm, word, pos, result, source, callback)
- searchLocals(vm, pos, word, function (var)
- callback(var, CompletionItemKind.Variable)
- end)
- for _, source in ipairs(vm.results.sources) do
- if source.isIndex then
- local index = source.bind
- if matchKey(word, index.key) then
- callback(index.key, CompletionItemKind.Property)
- end
- end
- end
- searchFields(word, result.parentValue, source, function (var)
- callback(var, CompletionItemKind.Field)
- end)
-end
-
-local function findClosePos(vm, pos)
- local curDis = math.maxinteger
- local parent = nil
- local inputSource = nil
- local function found(object, source)
- local dis = pos - source.finish
- if dis > 1 and dis < curDis then
- curDis = dis
- parent = object
- inputSource = source
- end
- end
- for _, source in ipairs(vm.results.sources) do
- found(source.bind, source)
- end
- if not parent then
- return nil
- end
- if parent.type ~= 'local' and parent.type ~= 'field' then
- return nil
- end
- local sep = inputSource.dot or inputSource.colon
- if not sep then
- return nil
- end
- if sep.finish > pos then
- return nil
- end
- -- 造个假的 DirtyName
- local source = {
- type = 'name',
- start = pos,
- finish = pos,
- object = sep.type == ':' and parent,
- isSuffix = true,
- [1] = '',
- }
- local result = {
- type = 'field',
- parent = parent,
- parentValue = parent.value,
- key = '',
- }
- return result, source
-end
-
-local function isContainPos(obj, pos)
- if obj.start <= pos and obj.finish + 1 >= pos then
- return true
- end
- return false
-end
-
-local function findString(vm, word, pos)
- local finishPos = pos + #word - 1
- for _, source in ipairs(vm.results.strings) do
- if isContainPos(source, finishPos) then
- return source
- end
- end
- return nil
-end
-
-local function findArgCount(args, pos)
- for i, arg in ipairs(args) do
- if isContainPos(arg, pos) then
- return i
- end
- end
- return #args + 1
-end
-
--- 找出范围包含pos的call
-local function findCall(vm, word, pos)
- local finishPos = pos + #word - 1
- local results = {}
- for _, call in ipairs(vm.results.calls) do
- if isContainPos(call.args, finishPos) then
- local n = findArgCount(call.args, finishPos)
- local var = call.lastObj.bind
- if var then
- results[#results+1] = {
- func = call.func,
- var = var,
- source = call.lastObj,
- select = n,
- args = call.args,
- }
- end
- end
- end
- if #results == 0 then
- return nil
- end
- -- 可能处于 'func1(func2(' 的嵌套中,因此距离越远的函数层级越低
- table.sort(results, function (a, b)
- return a.args.start < b.args.start
- end)
- return results[#results]
-end
-
-local function makeList(list, source)
- local mark = {}
- local function callback(var, defualt, data)
- local key
- if type(var) == 'string' then
- key = var
- else
- key = var.key
- end
- if mark[key] then
- return
- end
- mark[key] = true
- data = data or {}
- if var == key then
- data.label = var
- data.kind = defualt
- elseif var.source ~= source then
- data.label = var.key
- data.kind = getKind(var, defualt)
- data.detail = data.detail or getDetail(var)
- data.documentation = data.documentation or getDocument(var, source)
- else
- return
- end
- list[#list+1] = data
- end
- return callback
-end
-
-local function searchInResult(result, word, source, vm, pos, callback)
- if result.type == 'local' then
- if result.link then
- result = result.link
- end
- if source.isArg then
- searchAsArg(vm, word, pos, result, source, callback)
- elseif source.isLocal then
- searchAsLocal(vm, word, pos, result, source, callback)
- else
- searchAsGlobal(vm, word, pos, result, source, callback)
- end
- elseif result.type == 'field' then
- if source.isIndex then
- searchAsIndex(vm, word, pos, result, source, callback)
- elseif source.isSuffix then
- searchAsSuffix(result, source, word, callback)
- else
- searchAsGlobal(vm, word, pos, result, source, callback)
- end
- end
-end
-
-local function searchAllWords(text, vm, callback)
- if text == '' then
- return
- end
- if type(text) ~= 'string' then
- return
- end
- for _, source in ipairs(vm.results.sources) do
- if source.type == 'name' then
- if text ~= source[1] and matchKey(text, source[1]) then
- callback(source[1], CompletionItemKind.Text)
- end
- end
- end
-end
-
-local function searchSpecial(vm, pos, callback)
- -- 尝试 #
- local _, source = findSource(vm, pos, 2)
- if source and source.indexName and source[1].op == '#'
- then
- local label = source.indexName .. '+1'
- callback(label, CompletionItemKind.Snippet, {
- textEdit = {
- start = source.start,
- finish = source.finish,
- newText = ('[#%s] = '):format(label),
- }
- })
- end
-end
-
-local function clearList(list, source)
- local key = source[1]
- -- 清除自己
- for i, v in ipairs(list) do
- if v.label == key then
- table.remove(list, i)
- return
- end
- end
-end
-
-local function isValidResult(result)
- if not result then
- return false
- end
- if result.type == 'local' or result.type == 'field' then
- return true
- end
- return false
-end
-
-return function (vm, pos, word)
- local list = {}
- local callback = makeList(list)
- local inCall = findCall(vm, word, pos)
- local inString = findString(vm, word, pos)
- if inCall then
- searchInArg(vm, inCall, inString, callback)
- end
- searchSpecial(vm, pos, callback)
- if not inString then
- local result, source = findSource(vm, pos)
- if not isValidResult(result) then
- result, source = findClosePos(vm, pos)
- end
- if isValidResult(result) then
- callback = makeList(list, source)
- searchInResult(result, word, source, vm, pos, callback)
- searchAllWords(result.key, vm, callback)
- clearList(list, source)
- else
- searchAllWords(word, vm, callback)
- end
- end
- if #list == 0 then
- return nil
- end
- return list
-end