diff options
-rw-r--r-- | script-beta/core/completion.lua | 251 | ||||
-rw-r--r-- | script-beta/core/diagnostics/undefined-global.lua | 3 | ||||
-rw-r--r-- | script-beta/core/hover/arg.lua | 17 | ||||
-rw-r--r-- | script-beta/core/hover/init.lua | 10 | ||||
-rw-r--r-- | script-beta/core/hover/label.lua | 15 | ||||
-rw-r--r-- | script-beta/core/hover/name.lua | 21 | ||||
-rw-r--r-- | script-beta/utility.lua | 5 | ||||
-rw-r--r-- | test-beta/completion/init.lua | 84 |
8 files changed, 304 insertions, 102 deletions
diff --git a/script-beta/core/completion.lua b/script-beta/core/completion.lua index 099060de..9f3239c0 100644 --- a/script-beta/core/completion.lua +++ b/script-beta/core/completion.lua @@ -92,59 +92,8 @@ local function findParent(ast, text, offset) return nil, nil end -local function checkLocal(ast, word, offset, results) - local locals = guide.getVisibleLocals(ast.ast, offset) - for name, source in pairs(locals) do - if matchKey(word, name) then - results[#results+1] = { - label = name, - kind = ckind.Variable, - id = stack(function () - return { - detail = getLabel(source), - } - end), - } - end - end -end - -local function isSameSource(source, pos) - return source.start <= pos and source.finish >= pos -end - -local function checkField(word, start, parent, oop, results) - local used = {} - vm.eachField(parent, function (info) - local key = info.key - if key - and key:sub(1, 1) == 's' - and not isSameSource(info.source, start) then - local name = key:sub(3) - if not used[name] and matchKey(word, name) then - local kind = ckind.Field - local literal = vm.getLiteral(info.source) - if literal ~= nil then - kind = ckind.Enum - end - results[#results+1] = { - label = name, - kind = kind, - id = stack(function () - return { - detail = getLabel(info.source), - description = info.source.description, - } - end) - } - end - used[name] = true - end - end) -end - local function buildFunctionSnip(source) - local name = getName(source) + local name = getName(source):gsub('^.-[$.:]', '') local args = getArg(source) local id = 0 args = args:gsub('[^,]+', function (arg) @@ -171,6 +120,108 @@ local function buildFunction(results, source, oop, data) end end +local function buildDesc(source) + if source.description then + return source.description + end + local lib = vm.getLibrary(source) + if lib then + return lib.description + end +end + +local function checkLocal(ast, word, offset, results) + local locals = guide.getVisibleLocals(ast.ast, offset) + for name, source in pairs(locals) do + if matchKey(word, name) then + if vm.hasType(source, 'function') then + buildFunction(results, source, false, { + label = name, + kind = ckind.Function, + id = stack(function () + return { + detail = getLabel(source), + description = buildDesc(source), + } + end), + }) + else + results[#results+1] = { + label = name, + kind = ckind.Variable, + id = stack(function () + return { + detail = getLabel(source), + description = buildDesc(source), + } + end), + } + end + end + end +end + +local function isSameSource(source, pos) + return source.start <= pos and source.finish >= pos +end + +local function checkField(word, start, parent, oop, results) + local used = {} + vm.eachField(parent, function (info) + local key = info.key + if not key or key:sub(1, 1) ~= 's' then + return + end + if isSameSource(info.source, start) then + return + end + local name = key:sub(3) + if used[name] then + return + end + if not matchKey(word, name) then + used[name] = true + return + end + local kind = ckind.Field + if vm.hasType(info.source, 'function') then + if oop then + kind = ckind.Method + end + used[name] = true + buildFunction(results, info.source, oop, { + label = name, + kind = kind, + id = stack(function () + return { + detail = getLabel(info.source), + description = buildDesc(info.source), + } + end), + }) + else + if oop then + return + end + used[name] = true + local literal = vm.getLiteral(info.source) + if literal ~= nil then + kind = ckind.Enum + end + results[#results+1] = { + label = name, + kind = kind, + id = stack(function () + return { + detail = getLabel(info.source), + description = buildDesc(info.source), + } + end) + } + end + end) +end + local function checkLibrary(word, results) for name, lib in pairs(library.global) do if matchKey(word, name) then @@ -181,7 +232,7 @@ local function checkLibrary(word, results) id = stack(function () return { detail = getLabel(lib), - documentation = lib.description, + documentation = buildDesc(lib), } end), }) @@ -216,6 +267,99 @@ local function isInString(ast, offset) end) end +local keyWordMap = { +{'and'}, +{'break'}, +{'do', function (ast, text, start, results) + if config.config.completion.keywordSnippet then + guide.eachSourceContain() + results[#results+1] = { + label = 'do .. end', + kind = ckind.Snippet, + insertTextFormat = 2, + insertText = [[ +do + $0 +end]], + } + end +end}, +{'else'}, +{'elseif', function (ast, text, start, results) + if config.config.completion.keywordSnippet then + results[#results+1] = { + label = 'elseif .. then', + kind = ckind.Snippet, + insertTextFormat = 2, + insertText = [[elseif $1 then]], + } + end +end}, +{'end'}, +{'false'}, +{'for', function (ast, text, start, results) + if config.config.completion.keywordSnippet then + results[#results+1] = { + label = 'for .. in', + kind = ckind.Snippet, + insertTextFormat = 2, + insertText = [[ +for ${1:key, value} in ${2:pairs(t)} do + $0 +end]] + } + results[#results+1] = { + label = 'for i = ..', + kind = ckind.Snippet, + insertTextFormat = 2, + insertText = [[ +for ${1:i} = ${2:1}, ${3:10, 2} do + $0 +end]] + } + end +end}, +{'function', function (ast, text, start, results) + +end}, +{'goto'}, +{'if'}, +{'in'}, +{'local', function (ast, text, start, results) + if config.config.completion.keywordSnippet then + results[#results+1] = { + label = 'local function', + kind = ckind.Snippet, + } + end +end}, +{'nil'}, +{'not'}, +{'or'}, +{'repeat'}, +{'return'}, +{'then'}, +{'true'}, +{'until'}, +{'while'}, +} + +local function checkKeyWord(ast, text, start, word, results) + for _, data in ipairs(keyWordMap) do + local key = data[1] + if matchKey(word, key) then + results[#results+1] = { + label = key, + kind = ckind.Keyword, + } + local func = data[2] + if func then + func(ast, text, start, results) + end + end + end +end + local function tryWord(ast, text, offset, results) local word = findWord(text, offset) if not word then @@ -231,6 +375,7 @@ local function tryWord(ast, text, offset, results) local env = guide.getLocal(ast.ast, '_ENV', start) checkField(word, start, env, false, results) checkLibrary(word, results) + checkKeyWord(ast, text, start, word, results) end end checkCommon(word, text, results) diff --git a/script-beta/core/diagnostics/undefined-global.lua b/script-beta/core/diagnostics/undefined-global.lua index ed81ced3..ffb64582 100644 --- a/script-beta/core/diagnostics/undefined-global.lua +++ b/script-beta/core/diagnostics/undefined-global.lua @@ -14,6 +14,9 @@ return function (uri, callback) -- 遍历全局变量,检查所有没有 mode['set'] 的全局变量 local globals = vm.getGlobals(ast.ast) + if not globals then + return + end for key, infos in pairs(globals) do if infos.mode['set'] == true then goto CONTINUE diff --git a/script-beta/core/hover/arg.lua b/script-beta/core/hover/arg.lua index 9d557e3b..dc8db16c 100644 --- a/script-beta/core/hover/arg.lua +++ b/script-beta/core/hover/arg.lua @@ -1,7 +1,7 @@ local guide = require 'parser.guide' local vm = require 'vm' -local function asFunction(source, caller) +local function asFunction(source, oop) if not source.args then return '' end @@ -15,28 +15,21 @@ local function asFunction(source, caller) args[i] = ('%s'):format(vm.getType(arg)) end end - local methodDef, methodCall + local methodDef local parent = source.parent if parent and parent.type == 'setmethod' then methodDef = true end - if caller then - if caller.type == 'method' - or caller.type == 'getmethod' - or caller.type == 'setmethod' then - methodCall = true - end - end - if not methodDef and methodCall then + if not methodDef and oop then return table.concat(args, ', ', 2) else return table.concat(args, ', ') end end -return function (source, caller) +return function (source, oop) if source.type == 'function' then - return asFunction(source, caller) + return asFunction(source, oop) end return '' end diff --git a/script-beta/core/hover/init.lua b/script-beta/core/hover/init.lua index 63129c3e..47d4c5a6 100644 --- a/script-beta/core/hover/init.lua +++ b/script-beta/core/hover/init.lua @@ -11,9 +11,12 @@ local function getHoverAsFunction(source) local defs = 0 local protos = 0 local other = 0 + local oop = source.type == 'method' + or source.type == 'getmethod' + or source.type == 'setmethod' for _, value in ipairs(values) do if value.type == 'function' then - local label = getLabel(value.source, source) + local label = getLabel(value.source, oop) defs = defs + 1 labels[label] = (labels[label] or 0) + 1 if labels[label] == 1 then @@ -54,7 +57,10 @@ local function getHoverAsFunction(source) end local function getHoverAsValue(source) - local label = getLabel(source, source) + local oop = source.type == 'method' + or source.type == 'getmethod' + or source.type == 'setmethod' + local label = getLabel(source, oop) local desc = getDesc(source) return { label = label, diff --git a/script-beta/core/hover/label.lua b/script-beta/core/hover/label.lua index dd25d42e..21330b17 100644 --- a/script-beta/core/hover/label.lua +++ b/script-beta/core/hover/label.lua @@ -6,9 +6,9 @@ local getClass = require 'core.hover.class' local vm = require 'vm' local util = require 'utility' -local function asFunction(source, caller) - local name = buildName(source, caller) - local arg = buildArg(source, caller) +local function asFunction(source, oop) + local name = buildName(source, oop) + local arg = buildArg(source, oop) local rtn = buildReturn(source) local lines = {} lines[1] = ('function %s(%s)'):format(name, arg) @@ -28,7 +28,10 @@ local function asValue(source, title) type = nil end if lib then - name = ('%s<%s>'):format(name, buildName(lib)) + local libName = buildName(lib) + if name ~= libName then + name = ('%s<%s>'):format(name, buildName(lib)) + end end local pack = {} pack[#pack+1] = title @@ -108,9 +111,9 @@ local function asString(source) end end -return function (source, caller) +return function (source, oop) if source.type == 'function' then - return asFunction(source, caller) + return asFunction(source, oop) elseif source.type == 'local' or source.type == 'getlocal' or source.type == 'setlocal' then diff --git a/script-beta/core/hover/name.lua b/script-beta/core/hover/name.lua index 917bf96d..ea1906ed 100644 --- a/script-beta/core/hover/name.lua +++ b/script-beta/core/hover/name.lua @@ -5,14 +5,14 @@ local function asLocal(source) return guide.getName(source) end -local function asMethod(source, caller) +local function asMethod(source) local class = getClass(source.node) local node = class or guide.getName(source.node) or '?' local method = guide.getName(source) return ('%s:%s'):format(node, method) end -local function asField(source, caller) +local function asField(source) local class = getClass(source.node) local node = class or guide.getName(source.node) or '?' local method = guide.getName(source) @@ -27,12 +27,9 @@ local function asGlobal(source) return guide.getName(source) end -local function asLibrary(source, caller) +local function asLibrary(source, oop) local p - if caller - and (caller.type == 'method' - or caller.type == 'getmethod' - or caller.type == 'setmethod') then + if oop then if source.parent then for _, parent in ipairs(source.parent) do if parent.type == 'object' then @@ -58,9 +55,9 @@ local function asLibrary(source, caller) end end -local function buildName(source, caller) +local function buildName(source, oop) if source.library then - return asLibrary(source, caller) or '' + return asLibrary(source, oop) or '' end if source.type == 'local' or source.type == 'getlocal' @@ -73,18 +70,18 @@ local function buildName(source, caller) end if source.type == 'setmethod' or source.type == 'getmethod' then - return asMethod(source, caller) or '' + return asMethod(source) or '' end if source.type == 'setfield' or source.type == 'getfield' then - return asField(source, caller) or '' + return asField(source) or '' end if source.type == 'tablefield' then return asTableField(source) or '' end local parent = source.parent if parent then - return buildName(parent, caller) + return buildName(parent, oop) end return '' end diff --git a/script-beta/utility.lua b/script-beta/utility.lua index 9eaeb955..dfc7f510 100644 --- a/script-beta/utility.lua +++ b/script-beta/utility.lua @@ -420,9 +420,6 @@ function m.viewString(str, quo) end) return quo .. str:gsub([=[["\r\n]]=], esc) .. quo else - if str:find '\r' then - return m.viewString(str) - end local eqnum = #quo - 2 local fsymb = ']' .. ('='):rep(eqnum) .. ']' if not str:find(fsymb, 1, true) then @@ -437,7 +434,7 @@ function m.viewString(str, quo) return ssymb .. str .. fsymb end end - return m.viewString(str) + return m.viewString(str, '"') end end diff --git a/test-beta/completion/init.lua b/test-beta/completion/init.lua index bebe481b..5736d9b0 100644 --- a/test-beta/completion/init.lua +++ b/test-beta/completion/init.lua @@ -132,12 +132,28 @@ ass$ { { label = 'assert', - kind = CompletionItemKind.Function, + kind = CompletionItemKind.Function, }, { label = 'assert()', - kind = CompletionItemKind.Snippet, + kind = CompletionItemKind.Snippet, + }, +} + +TEST [[ +local function ffff(a, b) +end +ff$ +]] +{ + { + label = 'ffff', + kind = CompletionItemKind.Function, }, + { + label = 'ffff()', + kind = CompletionItemKind.Snippet, + } } TEST [[ @@ -177,6 +193,7 @@ t.ab$ TEST [[ local mt = {} +mt.ggg = 1 function mt:get(a, b) return 1 end @@ -186,16 +203,15 @@ mt:g$ { label = 'get', kind = CompletionItemKind.Method, - documentation = EXISTS, - detail = EXISTS, }, { label = 'get()', kind = CompletionItemKind.Snippet, - documentation = EXISTS, - insertText = EXISTS, - detail = EXISTS, }, + { + label = 'ggg', + kind = CompletionItemKind.Text, + } } TEST [[ @@ -205,15 +221,10 @@ loc$ { label = 'collectgarbage', kind = CompletionItemKind.Function, - documentation = EXISTS, - detail = EXISTS, }, { label = 'collectgarbage()', kind = CompletionItemKind.Snippet, - documentation = EXISTS, - detail = EXISTS, - insertText = EXISTS, }, { label = 'local', @@ -222,11 +233,58 @@ loc$ { label = 'local function', kind = CompletionItemKind.Snippet, - insertText = EXISTS, } } TEST [[ +do$ +]] +{ + { + label = 'dofile', + kind = CompletionItemKind.Function, + }, + { + label = 'dofile()', + kind = CompletionItemKind.Snippet, + }, + { + label = 'load', + kind = CompletionItemKind.Function, + }, + { + label = 'load()', + kind = CompletionItemKind.Snippet, + }, + { + label = 'loadfile', + kind = CompletionItemKind.Function, + }, + { + label = 'loadfile()', + kind = CompletionItemKind.Snippet, + }, + { + label = 'do', + kind = CompletionItemKind.Keyword, + }, + { + label = 'do .. end', + kind = CompletionItemKind.Snippet, + } +} + +TEST [[ +while true d$ +]] +{ + { + label = 'do', + kind = CompletionItemKind.Keyword, + }, +} + +TEST [[ t.a = {} t.b = {} t.$ |