diff options
author | 最萌小汐 <sumneko@hotmail.com> | 2021-05-08 16:20:30 +0800 |
---|---|---|
committer | 最萌小汐 <sumneko@hotmail.com> | 2021-05-08 16:20:30 +0800 |
commit | b5dd953912738cac05d8292eb080c6860f18d418 (patch) | |
tree | eba01883c6989f7b3c814cfba755246d22869431 | |
parent | 5e0c1dfa6beaf4431d7fae3e392aab7e7da34213 (diff) | |
parent | f3bf7d8fcf18f8fb5b07e17236356012732ee46a (diff) | |
download | lua-language-server-b5dd953912738cac05d8292eb080c6860f18d418.zip |
Merge remote-tracking branch 'origin/master' into 2.0.0
m--------- | 3rd/bee.lua | 0 | ||||
m--------- | 3rd/luamake | 0 | ||||
-rw-r--r-- | changelog.md | 41 | ||||
-rw-r--r-- | locale/en-us/script.lua | 2 | ||||
-rw-r--r-- | locale/zh-cn/script.lua | 2 | ||||
-rw-r--r-- | make.lua | 2 | ||||
-rw-r--r-- | script/config.lua | 3 | ||||
-rw-r--r-- | script/core/completion.lua | 105 | ||||
-rw-r--r-- | script/core/folding.lua | 4 | ||||
-rw-r--r-- | script/core/guide2.lua | 13 | ||||
-rw-r--r-- | script/core/highlight.lua | 91 | ||||
-rw-r--r-- | script/core/hover/description.lua | 8 | ||||
-rw-r--r-- | script/parser/ast.lua | 85 | ||||
-rw-r--r-- | script/parser/grammar.lua | 49 | ||||
-rw-r--r-- | script/parser/luadoc.lua | 18 | ||||
-rw-r--r-- | script/provider/provider.lua | 2 | ||||
-rw-r--r-- | script/utility.lua | 37 | ||||
-rw-r--r-- | test/completion/init.lua | 202 | ||||
-rw-r--r-- | test/crossfile/hover.lua | 30 | ||||
-rw-r--r-- | test/diagnostics/init.lua | 8 | ||||
-rw-r--r-- | test/document_symbol/init.lua | 32 |
21 files changed, 470 insertions, 264 deletions
diff --git a/3rd/bee.lua b/3rd/bee.lua -Subproject 3e2bf12fe97c0b337694dbb24ef8fb5c0f48252 +Subproject 28a9af609cbc1c6b787e28a5a946a96164103f2 diff --git a/3rd/luamake b/3rd/luamake -Subproject 4979b37ede5eb7a0d28d70377855374c5d45427 +Subproject 36a40b9a9cb044564bca7cef7d2cf244b22d781 diff --git a/changelog.md b/changelog.md index b3281ef9..6dc280f2 100644 --- a/changelog.md +++ b/changelog.md @@ -1,21 +1,40 @@ # changelog +## 1.21.1 +`2021-5-8` +* `FIX` [#529](https://github.com/sumneko/lua-language-server/issues/529) + +## 1.21.0 +`2021-5-7` +* `NEW` setting: `completion.showParams` +* `NEW` `LuaDoc`: supports multiline comments +* `NEW` `LuaDoc`: tail comments support lua string + +## 1.20.5 +`2021-4-30` +* `NEW` setting: `completion.autoRequire` +* `NEW` setting: `hover.enumsLimit` +* `CHG` folding: supports `-- #region` +* `FIX` completion: details may be suspended +* `FIX` [#522](https://github.com/sumneko/lua-language-server/issues/522) +* `FIX` [#523](https://github.com/sumneko/lua-language-server/issues/523) + ## 1.20.4 `2021-4-13` -`NEW` diagnostic: `deprecated` -`FIX` [#464](https://github.com/sumneko/lua-language-server/issues/464) -`FIX` [#497](https://github.com/sumneko/lua-language-server/issues/497) -`FIX` [#502](https://github.com/sumneko/lua-language-server/issues/502) +* `NEW` diagnostic: `deprecated` +* `FIX` [#464](https://github.com/sumneko/lua-language-server/issues/464) +* `FIX` [#497](https://github.com/sumneko/lua-language-server/issues/497) +* `FIX` [#502](https://github.com/sumneko/lua-language-server/issues/502) ## 1.20.3 `2021-4-6` -`FIX` [#479](https://github.com/sumneko/lua-language-server/issues/479) -`FIX` [#483](https://github.com/sumneko/lua-language-server/issues/483) -`FIX` [#485](https://github.com/sumneko/lua-language-server/issues/485) -`FIX` [#487](https://github.com/sumneko/lua-language-server/issues/487) -`FIX` [#488](https://github.com/sumneko/lua-language-server/issues/488) -`FIX` [#490](https://github.com/sumneko/lua-language-server/issues/490) -`FIX` [#495](https://github.com/sumneko/lua-language-server/issues/495) +* `FIX` [#479](https://github.com/sumneko/lua-language-server/issues/479) +* `FIX` [#483](https://github.com/sumneko/lua-language-server/issues/483) +* `FIX` [#485](https://github.com/sumneko/lua-language-server/issues/485) +* `FIX` [#487](https://github.com/sumneko/lua-language-server/issues/487) +* `FIX` [#488](https://github.com/sumneko/lua-language-server/issues/488) +* `FIX` [#490](https://github.com/sumneko/lua-language-server/issues/490) +* `FIX` [#495](https://github.com/sumneko/lua-language-server/issues/495) ## 1.20.2 `2021-4-2` diff --git a/locale/en-us/script.lua b/locale/en-us/script.lua index 9fbcb72e..69f97bb1 100644 --- a/locale/en-us/script.lua +++ b/locale/en-us/script.lua @@ -94,6 +94,7 @@ PARSER_UNEXPECT_SYMBOL = 'Unexpected symbol `{symbol}` .' PARSER_UNKNOWN_TAG = 'Unknown attribute.' PARSER_MULTI_TAG = 'Dose not support multi attributes.' PARSER_UNEXPECT_LFUNC_NAME = 'Local function can only use identifiers as name.' +PARSER_UNEXPECT_EFUNC_NAME = 'Function as expression cannot be named.' PARSER_ERR_LCOMMENT_END = 'Multi-line annotations should be closed by `{symbol}` .' PARSER_ERR_C_LONG_COMMENT = 'Lua should use `--[[ ]]` for multi-line annotations.' PARSER_ERR_LSTRING_END = 'Long string should be closed by `{symbol}` .' @@ -153,6 +154,7 @@ HOVER_STRING_BYTES = '{} bytes' HOVER_STRING_CHARACTERS = '{} bytes, {} characters' HOVER_MULTI_DEF_PROTO = '({} definitions, {} prototypes)' HOVER_MULTI_PROTO_NOT_FUNC = '({} non functional definition)' +HOVER_MORE_ENUMS = '|...(+{})' HOVER_USE_LUA_PATH = '(Search path: `{}`)' HOVER_EXTENDS = 'Expand to {}' diff --git a/locale/zh-cn/script.lua b/locale/zh-cn/script.lua index ab369a8e..e949ad31 100644 --- a/locale/zh-cn/script.lua +++ b/locale/zh-cn/script.lua @@ -94,6 +94,7 @@ PARSER_UNEXPECT_SYMBOL = '未知的符号 `{symbol}` 。' PARSER_UNKNOWN_TAG = '不支持的属性。' PARSER_MULTI_TAG = '只能设置一个属性。' PARSER_UNEXPECT_LFUNC_NAME = '局部函数只能使用标识符作为名称。' +PARSER_UNEXPECT_EFUNC_NAME = '函数作为表达式时不能命名。' PARSER_ERR_LCOMMENT_END = '应使用`{symbol}`来关闭多行注释。' PARSER_ERR_C_LONG_COMMENT = 'Lua应使用`--[[ ]]`来进行多行注释。' PARSER_ERR_LSTRING_END = '应使用`{symbol}`来关闭长字符串。' @@ -152,6 +153,7 @@ HOVER_STRING_BYTES = '{} 个字节' HOVER_STRING_CHARACTERS = '{} 个字节,{} 个字符' HOVER_MULTI_DEF_PROTO = '({} 个定义,{} 个原型)' HOVER_MULTI_PROTO_NOT_FUNC = '({} 个非函数定义)' +HOVER_MORE_ENUMS = '|...(+{})' HOVER_USE_LUA_PATH = '(搜索路径: `{}`)' HOVER_EXTENDS = '展开为 {}' @@ -1,7 +1,5 @@ local lm = require 'luamake' -lm.target = 'x64' - if lm.plat == "macos" then lm.flags = { "-mmacosx-version-min=10.13", diff --git a/script/config.lua b/script/config.lua index 7991e1ad..97df7c17 100644 --- a/script/config.lua +++ b/script/config.lua @@ -164,6 +164,8 @@ local ConfigTemplate = { keywordSnippet = {'Replace', String}, displayContext = {6, Integer}, workspaceWord = {true, Boolean}, + autoRequire = {true, Boolean}, + showParams = {true, Boolean}, }, signatureHelp = { enable = {true, Boolean}, @@ -175,6 +177,7 @@ local ConfigTemplate = { viewNumber = {true, Boolean}, fieldInfer = {3000, Integer}, previewFields = {100, Integer}, + enumsLimit = {5, Integer}, }, color = { mode = {'Semantic', String}, diff --git a/script/core/completion.lua b/script/core/completion.lua index 3ed2b070..0a5f688e 100644 --- a/script/core/completion.lua +++ b/script/core/completion.lua @@ -48,9 +48,7 @@ local function resolveStack(id) return nil end - -- 当进行新的 resolve 时,放弃当前的 resolve - await.close('completion.resolve') - return await.await(callback, 'completion.resolve') + return callback() end local function trim(str) @@ -123,17 +121,9 @@ local function findParentInStringIndex(ast, text, offset) return parent.node, false end -local function buildFunctionSnip(source, oop) +local function buildFunctionSnip(source, value, oop) local name = getName(source):gsub('^.+[$.:]', '') - local defs = vm.getDefs(source, 0) - local args = '' - for _, def in ipairs(defs) do - local defArgs = getArg(def, oop) - if defArgs ~= '' then - args = defArgs - break - end - end + local args = getArg(value, oop) local id = 0 args = args:gsub('[^,]+', function (arg) id = id + 1 @@ -193,7 +183,7 @@ local function buildDesc(source) return md:string() end -local function buildFunction(results, source, oop, data) +local function buildFunction(results, source, value, oop, data) local snipType = config.config.completion.callSnippet if snipType == 'Disable' or snipType == 'Both' then results[#results+1] = data @@ -201,8 +191,7 @@ local function buildFunction(results, source, oop, data) if snipType == 'Both' or snipType == 'Replace' then local snipData = util.deepCopy(data) snipData.kind = define.CompletionItemKind.Snippet - snipData.label = snipData.label .. '()' - snipData.insertText = buildFunctionSnip(source, oop) + snipData.insertText = buildFunctionSnip(source, value, oop) snipData.insertTextFormat = 2 snipData.id = stack(function () return { @@ -255,6 +244,26 @@ local function isSameSource(ast, source, pos) return source.start <= pos and source.finish >= pos end +local function getParams(func, oop) + if not func.args then + return '()' + end + local args = {} + for _, arg in ipairs(func.args) do + if arg.type == '...' then + args[#args+1] = '...' + elseif arg.type == 'doc.type.arg' then + args[#args+1] = arg.name[1] + else + args[#args+1] = arg[1] + end + end + if oop and args[1] ~= '...' then + table.remove(args, 1) + end + return '(' .. table.concat(args, ', ') .. ')' +end + local function checkLocal(ast, word, offset, results) local locals = searcher.getVisibleLocals(ast.ast, offset) for name, source in pairs(locals) do @@ -265,16 +274,23 @@ local function checkLocal(ast, word, offset, results) goto CONTINUE end if vm.hasType(source, 'function') then - buildFunction(results, source, false, { - label = name, - kind = define.CompletionItemKind.Function, - id = stack(function () - return { - detail = buildDetail(source), - description = buildDesc(source), - } - end), - }) + for _, def in ipairs(vm.getDefs(source, 0)) do + if def.type == 'function' + or def.type == 'doc.type.function' then + local funcLabel = name .. getParams(def, false) + buildFunction(results, source, def, false, { + label = funcLabel, + insertText = name, + kind = define.CompletionItemKind.Function, + id = stack(function () + return { + detail = buildDetail(source), + description = buildDesc(source), + } + end), + }) + end + end else results[#results+1] = { label = name, @@ -292,6 +308,9 @@ local function checkLocal(ast, word, offset, results) end local function checkModule(ast, word, offset, results) + if not config.config.completion.autoRequire then + return + end local locals = searcher.getVisibleLocals(ast.ast, offset) for uri in files.eachFile() do if files.eq(uri, searcher.getUri(ast.ast)) then @@ -400,15 +419,17 @@ end local function checkFieldThen(name, src, word, start, offset, parent, oop, results) local value = searcher.getObjectValue(src) or src local kind = define.CompletionItemKind.Field - if value.type == 'function' then + if value.type == 'function' + or value.type == 'doc.type.function' then if oop then kind = define.CompletionItemKind.Method else kind = define.CompletionItemKind.Function end - buildFunction(results, src, oop, { + buildFunction(results, src, value, oop, { label = name, kind = kind, + insertText = name:match '^[^(]+', deprecated = vm.isDeprecated(src) or nil, id = stack(function () return { @@ -469,8 +490,28 @@ local function checkFieldOfRefs(refs, ast, word, start, offset, parent, oop, res if not matchKey(word, name, count >= 100) then goto CONTINUE end + local funcLabel + if config.config.completion.showParams then + local value = guide.getObjectValue(src) or src + if value.type == 'function' + or value.type == 'doc.type.function' then + funcLabel = name .. getParams(value, oop) + fields[funcLabel] = src + fields[name] = false + count = count + 1 + if value.type == 'function' and value.bindDocs then + for _, doc in ipairs(value.bindDocs) do + if doc.type == 'doc.overload' then + funcLabel = name .. getParams(doc.overload, oop) + fields[funcLabel] = doc.overload + end + end + end + goto CONTINUE + end + end local last = fields[name] - if not last then + if last == nil then fields[name] = src count = count + 1 goto CONTINUE @@ -490,7 +531,9 @@ local function checkFieldOfRefs(refs, ast, word, start, offset, parent, oop, res ::CONTINUE:: end for name, src in util.sortPairs(fields) do - checkFieldThen(name, src, word, start, offset, parent, oop, results) + if src then + checkFieldThen(name, src, word, start, offset, parent, oop, results) + end end end @@ -543,7 +586,7 @@ local function checkCommon(myUri, word, text, offset, results) results.enableCommon = true local used = {} for _, result in ipairs(results) do - used[result.label] = true + used[result.label:match '^[^(]*'] = true end for _, data in ipairs(keyWordMap) do used[data[1]] = true diff --git a/script/core/folding.lua b/script/core/folding.lua index d089b816..1bbae944 100644 --- a/script/core/folding.lua +++ b/script/core/folding.lua @@ -1,5 +1,6 @@ -local files = require "files" +local files = require "files" local searcher = require "core.searcher" +local util = require 'utility' local Care = { ['function'] = function (source, text, results) @@ -92,6 +93,7 @@ local Care = { end, ['comment.short'] = function (source, text, results, status) local ltext = source.text:lower() + ltext = util.trim(ltext, 'left') if ltext:sub(1, #'region') == 'region' or ltext:sub(1, #'#region') == '#region' then if not status.regions then diff --git a/script/core/guide2.lua b/script/core/guide2.lua index 64192297..576c0c20 100644 --- a/script/core/guide2.lua +++ b/script/core/guide2.lua @@ -1,4 +1,6 @@ local util = require 'utility' +local config = require 'config' +local lang = require 'language' local error = error local type = type local next = next @@ -1845,6 +1847,8 @@ function m.checkSameSimpleByBindDocs(status, obj, start, pushQueue, mode) if obj.type == '...' then results[#results+1] = doc end + elseif doc.type == 'doc.overload' then + results[#results+1] = doc.overload end end for _, res in ipairs(results) do @@ -3401,7 +3405,14 @@ function m.mergeTypes(types) end end) - return tableConcat(results, '|') + local enumsLimit = config.config.hover.enumsLimit + if #results > enumsLimit then + return tableConcat(results, '|', 1, enumsLimit) + .. lang.script('HOVER_MORE_ENUMS', #results - enumsLimit) + else + return tableConcat(results, '|') + end + end function m.getClassExtends(class) diff --git a/script/core/highlight.lua b/script/core/highlight.lua index 75adcb1f..b070c77e 100644 --- a/script/core/highlight.lua +++ b/script/core/highlight.lua @@ -3,6 +3,7 @@ local files = require 'files' local vm = require 'vm' local define = require 'proto.define' local findSource = require 'core.find-source' +local util = require 'utility' local function eachRef(source, callback) local results = searcher.requestReference(source) @@ -138,6 +139,88 @@ local function findKeyWord(ast, text, offset, callback) end) end +local function isRegion(str) + if str:sub(1, #'region') == 'region' + or str:sub(1, #'#region') == '#region' then + return true + end + return false +end + +local function isEndRegion(str) + if str:sub(1, #'endregion') == 'endregion' + or str:sub(1, #'#endregion') == '#endregion' then + return true + end + return false +end + +local function checkRegion(ast, text, offset, callback) + local count + local start, finish + local selected + for i, comment in ipairs(ast.comms) do + if comment.type == 'comment.short' then + if comment.start <= offset + and comment.finish >= offset then + local ltext = comment.text:lower() + ltext = util.trim(ltext, 'left') + if isRegion(ltext) then + start = comment.start - 2 + count = 1 + selected = i + elseif isEndRegion(ltext) then + finish = comment.finish + count = 1 + selected = i + else + return + end + break + end + end + end + if not selected then + return + end + if start then + for i = selected + 1, #ast.comms do + local comment = ast.comms[i] + if comment.type == 'comment.short' then + local ltext = comment.text:lower() + ltext = util.trim(ltext, 'left') + if isRegion(ltext) then + count = count + 1 + elseif isEndRegion(ltext) then + count = count - 1 + if count == 0 then + callback(start, comment.finish) + return + end + end + end + end + end + if finish then + for i = selected - 1, 1, -1 do + local comment = ast.comms[i] + if comment.type == 'comment.short' then + local ltext = comment.text:lower() + ltext = util.trim(ltext, 'left') + if isEndRegion(ltext) then + count = count + 1 + elseif isRegion(ltext) then + count = count - 1 + if count == 0 then + callback(comment.start - 2, finish) + return + end + end + end + end + end +end + local accept = { ['label'] = true, ['goto'] = true, @@ -255,6 +338,14 @@ return function (uri, offset) } end) + checkRegion(ast, text, offset, function (start, finish) + results[#results+1] = { + start = start, + finish = finish, + kind = define.DocumentHighlightKind.Text + } + end) + if #results == 0 then return nil end diff --git a/script/core/hover/description.lua b/script/core/hover/description.lua index 33cae0a6..85224c66 100644 --- a/script/core/hover/description.lua +++ b/script/core/hover/description.lua @@ -170,7 +170,7 @@ local function buildEnumChunk(docType, name) or (enum.additional and '+>') or ' |', enum[1], - enum.comment and (' -- %s'):format(enum.comment:gsub('[\r\n]+', ' ')) or '' + enum.comment and (' -- %s'):format(enum.comment) or '' ) end return table.concat(lines, '\n') @@ -264,7 +264,7 @@ local function getFunctionComment(source) comments[#comments+1] = '\n' comments[#comments+1] = ('@*param* `%s` — %s'):format( doc.param[1], - doc.comment.text:gsub('[\r\n]+', ' ') + doc.comment.text ) comments[#comments+1] = '\n' end @@ -280,9 +280,9 @@ local function getFunctionComment(source) end if doc.comment then if #name == 0 then - comments[#comments+1] = ('@*return* — %s'):format(doc.comment.text:gsub('[\r\n]+', ' ')) + comments[#comments+1] = ('@*return* — %s'):format(doc.comment.text) else - comments[#comments+1] = ('@*return* `%s` — %s'):format(table.concat(name, ','), doc.comment.text:gsub('[\r\n]+', ' ')) + comments[#comments+1] = ('@*return* `%s` — %s'):format(table.concat(name, ','), doc.comment.text) end else if #name == 0 then diff --git a/script/parser/ast.lua b/script/parser/ast.lua index 0a188da4..4f27d37d 100644 --- a/script/parser/ast.lua +++ b/script/parser/ast.lua @@ -9,7 +9,12 @@ local tableSort = table.sort _ENV = nil -local State +local DefaultState = { + lua = '', + options = {}, +} + +local State = DefaultState local PushError local PushDiag local PushComment @@ -277,7 +282,7 @@ local Defs = { type = 'comment.long', start = start, finish = finish - 1, - text = '', + text = str, } if not close then local endSymbol = ']' .. ('='):rep(afterEq-beforeEq) .. ']' @@ -318,7 +323,7 @@ local Defs = { } end end, - CLongComment = function (start1, finish1, start2, finish2) + CLongComment = function (start1, finish1, str, start2, finish2) if State.options.nonstandardSymbol and State.options.nonstandardSymbol['/**/'] then else PushError { @@ -344,7 +349,7 @@ local Defs = { type = 'comment.clong', start = start1, finish = finish2 - 1, - text = '', + text = str, } end, CCommentPrefix = function (start, finish, commentFinish) @@ -983,19 +988,7 @@ local Defs = { finish = start, } end, - Function = function (functionStart, functionFinish, args, actions, endStart, endFinish) - actions.type = 'function' - actions.start = functionStart - actions.finish = endFinish - 1 - actions.args = args - actions.keyword= { - functionStart, functionFinish - 1, - endStart, endFinish - 1, - } - checkMissEnd(functionStart) - return actions - end, - NamedFunction = function (functionStart, functionFinish, name, args, actions, endStart, endFinish) + Function = function (functionStart, functionFinish, name, args, actions, endStart, endFinish) actions.type = 'function' actions.start = functionStart actions.finish = endFinish - 1 @@ -1006,7 +999,7 @@ local Defs = { } checkMissEnd(functionStart) if not name then - return + return actions end if name.type == 'getname' then name.type = 'setname' @@ -1030,35 +1023,49 @@ local Defs = { name.vstart = functionStart return name end, - LocalFunction = function (start, functionStart, functionFinish, name, args, actions, endStart, endFinish) - actions.type = 'function' - actions.start = start - actions.finish = endFinish - 1 - actions.args = args - actions.keyword= { - functionStart, functionFinish - 1, - endStart, endFinish - 1, - } - checkMissEnd(start) - - if not name then - return + LocalFunction = function (start, name) + if name.type == 'function' then + PushError { + type = 'MISS_NAME', + start = name.keyword[2] + 1, + finish = name.keyword[2] + 1, + } + return name end - - if name.type ~= 'getname' then + if name.type ~= 'setname' then PushError { type = 'UNEXPECT_LFUNC_NAME', start = name.start, finish = name.finish, } - return + return name end - local loc = createLocal(name, name.start, actions) + local loc = createLocal(name, name.start, name.value) loc.localfunction = true - loc.vstart = functionStart - - return loc + loc.vstart = name.value.start + return name + end, + NamedFunction = function (name) + if name.type == 'function' then + PushError { + type = 'MISS_NAME', + start = name.keyword[2] + 1, + finish = name.keyword[2] + 1, + } + end + return name + end, + ExpFunction = function (func) + if func.type ~= 'function' then + PushError { + type = 'UNEXPECT_EFUNC_NAME', + start = func.start, + finish = func.finish, + } + return func.value + end + return func end, Table = function (start, tbl, finish) tbl.type = 'table' @@ -1923,7 +1930,7 @@ local function init(state) end local function close() - State = nil + State = DefaultState PushError = function (...) end PushDiag = function (...) end PushComment = function (...) end diff --git a/script/parser/grammar.lua b/script/parser/grammar.lua index 53d174f3..01756c2a 100644 --- a/script/parser/grammar.lua +++ b/script/parser/grammar.lua @@ -88,13 +88,13 @@ end grammar 'Comment' [[ Comment <- LongComment / '--' ShortComment -LongComment <- ({} '--[' {} {:eq: '='* :} {} '[' +LongComment <- ({} '--[' {} {:eq: '='* :} {} '[' %nl? {(!CommentClose .)*} ((CommentClose / %nil) {})) -> LongComment / ( - {} '/*' {} - (!'*/' .)* + {} '/*' {} %nl? + {(!'*/' .)*} {} '*/' {} ) -> CLongComment @@ -319,7 +319,7 @@ ExpUnit <- Nil / Number / Dots / Table - / Function + / ExpFunction / Simple Simple <- {| Prefix (Sp Suffix)* |} @@ -327,7 +327,7 @@ Simple <- {| Prefix (Sp Suffix)* |} Prefix <- Sp ({} PL DirtyExp DirtyPR {}) -> Paren / Single -Single <- Name +Single <- !FUNCTION Name -> Single Suffix <- SuffixWithoutCall / ({} PL SuffixCall DirtyPR {}) @@ -377,8 +377,21 @@ NewIndex <- Sp ({} Index NeedAssign DirtyExp {}) NewField <- Sp ({} MustName ASSIGN DirtyExp {}) -> NewField +ExpFunction <- Function + -> ExpFunction Function <- FunctionBody -> Function +FunctionBody + <- FUNCTION FuncName FuncArgs + {| (!END Action)* |} + NeedEnd + / FUNCTION FuncName FuncArgsMiss + {| %nil |} + NeedEnd +FuncName <- !END {| Single (Sp SuffixWithoutCall)* |} + -> Simple + / %nil + FuncArgs <- Sp ({} PL {| FuncArg+ |} DirtyPR {}) -> FuncArgs / PL DirtyPR %nil @@ -386,12 +399,6 @@ FuncArgsMiss<- {} -> MissPL DirtyPR %nil FuncArg <- DOTS / Name / COMMA -FunctionBody<- FUNCTION FuncArgs - {| (!END Action)* |} - NeedEnd - / FUNCTION FuncArgsMiss - {| %nil |} - NeedEnd -- 纯占位,修改了 `relabel.lua` 使重复定义不抛错 Action <- !END . @@ -515,26 +522,16 @@ LocalNameList LocalName <- (MustName LocalAttr?) -> LocalName +NamedFunction + <- Function + -> NamedFunction + Call <- Simple -> SimpleCall LocalFunction - <- Sp ({} LOCAL FunctionNamedBody) + <- Sp ({} LOCAL Function) -> LocalFunction - -NamedFunction - <- FunctionNamedBody - -> NamedFunction -FunctionNamedBody - <- FUNCTION FuncName FuncArgs - {| (!END Action)* |} - NeedEnd - / FUNCTION FuncName FuncArgsMiss - {| %nil |} - NeedEnd -FuncName <- {| Single (Sp SuffixWithoutCall)* |} - -> Simple - / {} -> MissName %nil ]] grammar 'Lua' [[ diff --git a/script/parser/luadoc.lua b/script/parser/luadoc.lua index af5071b3..0edf5371 100644 --- a/script/parser/luadoc.lua +++ b/script/parser/luadoc.lua @@ -2,6 +2,7 @@ local m = require 'lpeglabel' local re = require 'parser.relabel' local lines = require 'parser.lines' local guide = require 'parser.guide' +local grammar = require 'parser.grammar' local TokenTypes, TokenStarts, TokenFinishs, TokenContents local Ci, Offset, pushError, Ct, NextComment, Lines @@ -990,16 +991,23 @@ local function convertTokens() end local function trimTailComment(text) + local comment = text if text:sub(1, 1) == '@' then - return text:sub(2) + comment = text:sub(2) end if text:sub(1, 1) == '#' then - return text:sub(2) + comment = text:sub(2) end if text:sub(1, 2) == '--' then - return text:sub(3) + comment = text:sub(3) end - return text + if comment:find '^%s*[\'"[]' then + local result = grammar(nil, comment:gsub('^%s+', ''), 'string') + if result then + comment = result[1][1] + end + end + return comment end local function buildLuaDoc(comment) @@ -1177,7 +1185,7 @@ local function bindDoc(sources, lns, binded) end bindGeneric(binded) local row = guide.positionOf(lns, lastDoc.finish) - local cstart, cfinish = guide.lineRange(lns, row) + local cstart, cfinish = guide.lineRange(lns, row) local nstart, nfinish = guide.lineRange(lns, row + 1) bindDocsBetween(sources, binded, bindSources, cstart, cfinish) if #bindSources == 0 then diff --git a/script/provider/provider.lua b/script/provider/provider.lua index 65993940..a6f4d9cc 100644 --- a/script/provider/provider.lua +++ b/script/provider/provider.lua @@ -550,6 +550,8 @@ proto.on('completionItem/resolve', function (item) if not item.data then return item end + await.close 'completion.resolve' + await.setID 'completion.resolve' local id = item.data.id local uri = item.data.uri --await.setPriority(1000) diff --git a/script/utility.lua b/script/utility.lua index a98bef92..04597a39 100644 --- a/script/utility.lua +++ b/script/utility.lua @@ -23,6 +23,14 @@ local utf8 = utf8 _ENV = nil +local function isInteger(n) + if mathType then + return mathType(n) == 'integer' + else + return type(n) == 'number' and n % 1 == 0 + end +end + local function formatNumber(n) if n == inf or n == -inf @@ -30,7 +38,7 @@ local function formatNumber(n) or n ~= n then -- IEEE 标准中,NAN 不等于自己。但是某些实现中没有遵守这个规则 return ('%q'):format(n) end - if mathType(n) == 'integer' then + if isInteger(n) then return tostring(n) end local str = ('%.10f'):format(n) @@ -38,14 +46,6 @@ local function formatNumber(n) return str end -local function isInteger(n) - if mathType then - return mathType(n) == 'integer' - else - return type(n) == 'number' and n % 1 == 0 - end -end - local TAB = setmetatable({}, { __index = function (self, n) self[n] = stringRep(' ', n) return self[n] @@ -204,7 +204,10 @@ function m.equal(a, b) end return true elseif tp1 == 'number' then - return mathAbs(a - b) <= 1e-10 + if mathAbs(a - b) <= 1e-10 then + return true + end + return tostring(a) == tostring(b) else return a == b end @@ -617,4 +620,18 @@ function m.sortByScore(tbl, callbacks) end) end +---裁剪字符串 +---@param str string +---@param mode? '"left"'|'"right"' +---@return string +function m.trim(str, mode) + if mode == "left" then + return str:gsub('^%s+', '') + end + if mode == "right" then + return str:gsub('%s+$', '') + end + return str:match '^%s*(%S+)%s*$' +end + return m diff --git a/test/completion/init.lua b/test/completion/init.lua index 22103896..89772853 100644 --- a/test/completion/init.lua +++ b/test/completion/init.lua @@ -60,6 +60,8 @@ local Cared = { ['deprecated'] = true, } +local IgnoreFunction = false + function TEST(script) return function (expect) files.removeAll() @@ -86,6 +88,16 @@ function TEST(script) end end end + if IgnoreFunction then + for i = #result, 1, -1 do + local item = result[i] + if item.label:find '%(' + and not item.label:find 'function' then + result[i] = result[#result] + result[#result] = nil + end + end + end assert(result) if expect.include then expect.include = nil @@ -175,11 +187,11 @@ ass$ ]] { { - label = 'assert', + label = 'assert(v, message)', kind = define.CompletionItemKind.Function, }, { - label = 'assert()', + label = 'assert(v, message)', kind = define.CompletionItemKind.Snippet, }, } @@ -201,11 +213,11 @@ _G.ass$ ]] { { - label = 'assert', + label = 'assert(v, message)', kind = define.CompletionItemKind.Function, }, { - label = 'assert()', + label = 'assert(v, message)', kind = define.CompletionItemKind.Snippet, }, } @@ -217,11 +229,11 @@ ff$ ]] { { - label = 'ffff', + label = 'ffff(a, b)', kind = define.CompletionItemKind.Function, }, { - label = 'ffff()', + label = 'ffff(a, b)', kind = define.CompletionItemKind.Snippet, } } @@ -285,11 +297,11 @@ mt:g$ ]] { { - label = 'get', + label = 'get(a, b)', kind = define.CompletionItemKind.Method, }, { - label = 'get()', + label = 'get(a, b)', kind = define.CompletionItemKind.Snippet, }, { @@ -311,15 +323,16 @@ loc$ kind = define.CompletionItemKind.Snippet, }, { - label = 'collectgarbage', + label = 'collectgarbage(opt, ...)', kind = define.CompletionItemKind.Function, }, { - label = 'collectgarbage()', + label = 'collectgarbage(opt, ...)', kind = define.CompletionItemKind.Snippet, }, } +IgnoreFunction = true TEST [[ do$ ]] @@ -332,50 +345,6 @@ do$ label = 'do .. end', kind = define.CompletionItemKind.Snippet, }, - { - label = 'dofile', - kind = define.CompletionItemKind.Function, - }, - { - label = 'dofile()', - kind = define.CompletionItemKind.Snippet, - }, - { - label = 'load', - kind = define.CompletionItemKind.Function, - }, - { - label = 'load()', - kind = define.CompletionItemKind.Snippet, - }, - { - label = 'loadfile', - kind = define.CompletionItemKind.Function, - }, - { - label = 'loadfile()', - kind = define.CompletionItemKind.Snippet, - }, - { - label = 'loadstring', - kind = define.CompletionItemKind.Function, - deprecated = true, - }, - { - label = 'loadstring()', - kind = define.CompletionItemKind.Snippet, - deprecated = true, - }, - { - label = 'module', - kind = define.CompletionItemKind.Function, - deprecated = true, - }, - { - label = 'module()', - kind = define.CompletionItemKind.Snippet, - deprecated = true, - }, } TEST [[ @@ -454,6 +423,7 @@ t. $ }, } +IgnoreFunction = false TEST [[ t.a = {} function t:b() @@ -462,7 +432,7 @@ t:$ ]] { { - label = 'b', + label = 'b()', kind = define.CompletionItemKind.Method, }, { @@ -507,6 +477,7 @@ TEST 'local s = "a:$"' (nil) TEST 'debug.$' (EXISTS) +IgnoreFunction = true TEST [[ local xxxx = { xxyy = 1, @@ -530,22 +501,6 @@ local t = { label = 'xxzz', kind = define.CompletionItemKind.Property, }, - { - label = 'next', - kind = define.CompletionItemKind.Function, - }, - { - label = 'next()', - kind = define.CompletionItemKind.Snippet, - }, - { - label = 'xpcall', - kind = define.CompletionItemKind.Function, - }, - { - label = 'xpcall()', - kind = define.CompletionItemKind.Snippet, - }, } TEST [[ @@ -1030,25 +985,10 @@ else$ label = 'ELSE', kind = define.CompletionItemKind.Enum, }, - { - label = 'select', - kind = define.CompletionItemKind.Function, - }, - { - label = 'select()', - kind = define.CompletionItemKind.Snippet, - }, - { - label = 'setmetatable', - kind = define.CompletionItemKind.Function, - }, - { - label = 'setmetatable()', - kind = define.CompletionItemKind.Snippet, - }, } Cared['insertText'] = true +IgnoreFunction = false TEST [[ local xpcal xpcal$ @@ -1059,11 +999,12 @@ xpcal$ kind = define.CompletionItemKind.Variable, }, { - label = 'xpcall', + label = 'xpcall(f, msgh, arg1, ...)', kind = define.CompletionItemKind.Function, + insertText = EXISTS, }, { - label = 'xpcall()', + label = 'xpcall(f, msgh, arg1, ...)', kind = define.CompletionItemKind.Snippet, insertText = EXISTS, }, @@ -1077,11 +1018,12 @@ mt:f$ ]] { { - label = 'f', + label = 'f(a, b, c)', kind = define.CompletionItemKind.Method, + insertText = EXISTS, }, { - label = 'f()', + label = 'f(a, b, c)', kind = define.CompletionItemKind.Snippet, insertText = 'f(${1:a: any}, ${2:b: any}, ${3:c: any})', }, @@ -1123,6 +1065,7 @@ end", }, } Cared['insertText'] = false +IgnoreFunction = true TEST [[ local function f() @@ -1143,22 +1086,6 @@ end label = 'elseif .. then', kind = define.CompletionItemKind.Snippet, }, - { - label = 'select', - kind = define.CompletionItemKind.Function, - }, - { - label = 'select()', - kind = define.CompletionItemKind.Snippet, - }, - { - label = 'setmetatable', - kind = define.CompletionItemKind.Function, - }, - { - label = 'setmetatable()', - kind = define.CompletionItemKind.Snippet, - }, } TEST [[ @@ -1259,17 +1186,18 @@ io$ ]] (EXISTS) +IgnoreFunction = false TEST [[ loadstring$ ]] { { - label = 'loadstring', + label = 'loadstring(text, chunkname)', kind = define.CompletionItemKind.Function, deprecated = true, }, { - label = 'loadstring()', + label = 'loadstring(text, chunkname)', kind = define.CompletionItemKind.Snippet, deprecated = true, }, @@ -1293,13 +1221,23 @@ loadstring$ ]] { { - label = 'loadstring', + label = 'loadstring()', kind = define.CompletionItemKind.Function, }, { label = 'loadstring()', kind = define.CompletionItemKind.Snippet, }, + { + label = 'loadstring(text, chunkname)', + deprecated = true, + kind = define.CompletionItemKind.Function, + }, + { + label = 'loadstring(text, chunkname)', + deprecated = true, + kind = define.CompletionItemKind.Snippet, + }, } TEST [[ @@ -1307,12 +1245,12 @@ debug.setcsta$ ]] { { - label = 'setcstacklimit', + label = 'setcstacklimit(limit)', kind = define.CompletionItemKind.Function, deprecated = true, }, { - label = 'setcstacklimit()', + label = 'setcstacklimit(limit)', kind = define.CompletionItemKind.Snippet, deprecated = true, }, @@ -1837,9 +1775,6 @@ end) TEST [[ --- JustTest ----@overload fun(list:table):string ----@overload fun(list:table, sep:string):string ----@overload fun(list:table, sep:string, i:number):string ---@param list table ---@param sep string ---@param i number @@ -1851,11 +1786,12 @@ zzz$ ]] { { - label = 'zzzzz', + label = 'zzzzz(list, sep, i, j)', kind = define.CompletionItemKind.Function, + insertText = EXISTS, }, { - label = 'zzzzz()', + label = 'zzzzz(list, sep, i, j)', kind = define.CompletionItemKind.Snippet, insertText = EXISTS, } @@ -2334,8 +2270,9 @@ end m.f$ ]]{ { - label = "f", + label = "f()", kind = define.CompletionItemKind.Function, + insertText = EXISTS, }, { label = "f()", @@ -2541,3 +2478,32 @@ TEST [[ }, } } + +Cared['insertText'] = true +TEST [[ +---@overload fun(a: any, b: any) +local function zzzz(a) end +zzzz$ +]] +{ + { + label = 'zzzz(a)', + kind = define.CompletionItemKind.Function, + insertText = 'zzzz', + }, + { + label = 'zzzz(a)', + kind = define.CompletionItemKind.Snippet, + insertText = 'zzzz(${1:a: any})', + }, + { + label = 'zzzz(a, b)', + kind = define.CompletionItemKind.Function, + insertText = 'zzzz', + }, + { + label = 'zzzz(a, b)', + kind = define.CompletionItemKind.Snippet, + insertText = 'zzzz(${1:a: any}, ${2:b: any})', + }, +} diff --git a/test/crossfile/hover.lua b/test/crossfile/hover.lua index 521f5a49..bf56b39a 100644 --- a/test/crossfile/hover.lua +++ b/test/crossfile/hover.lua @@ -731,3 +731,33 @@ hover = { label = 'field Food.firstField: integer = 0', name = 'food.firstField', }} + +TEST {{ path = 'a.lua', content = '', }, { + path = 'b.lua', + content = [[ +--[=[ +I'm a multiline comment +]=] +local <?food?> +]] +}, +hover = { + label = 'local food: any', + name = 'food', + description = "I'm a multiline comment\n" +}} + +TEST {{ path = 'a.lua', content = '', }, { + path = 'b.lua', + content = [[ +---@return string # 'this is a tab `\t`' +local function <?f?>() end +]] +}, +hover = { + label = [[ +function f() + -> string]], + name = 'food', + description = "@*return* — this is a tab `\t`" +}} diff --git a/test/diagnostics/init.lua b/test/diagnostics/init.lua index 00a2cda8..d4bffdb5 100644 --- a/test/diagnostics/init.lua +++ b/test/diagnostics/init.lua @@ -100,7 +100,7 @@ local <!t!> = {} ]] TEST([[ -<!local function x() +local <!function x() end!> ]], [[ @@ -119,9 +119,9 @@ local <!x!> ]] TEST([[ -<!local function x() +local <!function x() end!> -<!local function y() +local <!function y() x() end!> ]], @@ -363,7 +363,7 @@ local f;f = <!function () end!> ]] TEST [[ -<!local function f() end!> +local <!function f() end!> ]] config.config.diagnostics.disable['unused-local'] = nil diff --git a/test/document_symbol/init.lua b/test/document_symbol/init.lua index d9f1bec3..718089e2 100644 --- a/test/document_symbol/init.lua +++ b/test/document_symbol/init.lua @@ -77,9 +77,9 @@ end name = 'f', detail = 'function ()', kind = define.SymbolKind.Function, - range = {1, 22}, + range = {7, 22}, selectionRange = {16, 16}, - valueRange = {1, 22}, + valueRange = {7, 22}, } } @@ -227,9 +227,9 @@ local z name = 'f', detail = 'function ()', kind = define.SymbolKind.Function, - range = {13, 79}, + range = {19, 79}, selectionRange = {28, 28}, - valueRange = {13, 79}, + valueRange = {19, 79}, children = { [1] = { name = 'x', @@ -360,9 +360,9 @@ g = 1 name = 'g', detail = 'function ()', kind = define.SymbolKind.Function, - range = {1, 22}, + range = {7, 22}, selectionRange = {16, 16}, - valueRange = {1, 22}, + valueRange = {7, 22}, }, [2] = { name = 'g', @@ -449,6 +449,14 @@ local function range = {7, 7}, selectionRange = {7, 7}, }, + [2] = { + name = "", + detail = "function ()", + kind = 12, + range = {15, 22}, + selectionRange = {15, 15}, + valueRange = {15, 22}, + }, } TEST [[ @@ -496,17 +504,17 @@ end name = 'x', detail = 'function ()', kind = define.SymbolKind.Function, - range = {1, 22}, + range = {7, 22}, selectionRange = {16, 16}, - valueRange = {1, 22}, + valueRange = {7, 22}, }, [2] = { name = 'f', detail = 'function ()', kind = define.SymbolKind.Function, - range = {25, 58}, + range = {31, 58}, selectionRange = {40, 40}, - valueRange = {25, 58}, + valueRange = {31, 58}, children = { [1] = { name = 'c', @@ -563,9 +571,9 @@ end name = 'f', detail = 'function (a, b)', kind = define.SymbolKind.Function, - range = {15, 40}, + range = {21, 40}, selectionRange = {30, 30}, - valueRange = {15, 40}, + valueRange = {21, 40}, children = { [1] = { name = 'a', |