diff options
author | uhziel <uhziel@gmail.com> | 2020-12-15 14:53:59 +0800 |
---|---|---|
committer | uhziel <uhziel@gmail.com> | 2020-12-15 14:53:59 +0800 |
commit | 8e55293116809cd46c9f3dce7c972e8ee77af840 (patch) | |
tree | 487da1bb0a1b0980870dbab7309fd2f026954b4b | |
parent | e7df5a89d015dacd613cc9cdeb7539386884a3eb (diff) | |
parent | f3ec5825e3c6a8090a020097e088f26718c316bb (diff) | |
download | lua-language-server-8e55293116809cd46c9f3dce7c972e8ee77af840.zip |
Merge branch 'master' into diagnostic-undefined-field
29 files changed, 446 insertions, 37 deletions
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..33daf9af --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,32 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Environment (please complete the following information):** + - OS: [e.g. Windows, macOS, Ubuntu] + - Is WSL remote? + - Client: [e.g. VSCode, neovim] + +**Additional context** +Add any other context about the problem here. diff --git a/.vscode/settings.json b/.vscode/settings.json index 28cfacbe..92e6ec8e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -35,5 +35,5 @@ "Lua.awakened.cat": true, "Lua.develop.enable": true, "Lua.develop.debuggerPort": 11413, - "Lua.intelliSense.searchDepth": 5 + "Lua.intelliSense.searchDepth": 0 } diff --git a/3rd/bee.lua b/3rd/bee.lua -Subproject bb5e94e2dc0822c2f36b24bdcb12f361fda5cdd +Subproject bb6094a71d3cd41f0af22704cc1905330d4cc1f diff --git a/changelog.md b/changelog.md index d7a1755c..7057ca28 100644 --- a/changelog.md +++ b/changelog.md @@ -2,6 +2,10 @@ ## 1.7.0 * `CHG` diagnostic: `unused-function` ignores function with `<close>` +* `CHG` semantic: not cover local call +* `FIX` semantic: tokens may not be updated correctly +* `FIX` completion: require path broken +* `FIX` [#291](https://github.com/sumneko/lua-language-server/issues/291) ## 1.6.0 `2020-12-14` diff --git a/locale/zh-cn/script.lua b/locale/zh-cn/script.lua index 3dda7699..4e43024f 100644 --- a/locale/zh-cn/script.lua +++ b/locale/zh-cn/script.lua @@ -2,7 +2,7 @@ DIAG_LINE_ONLY_SPACE = '只有空格的空行。' DIAG_LINE_POST_SPACE = '后置空格。' DIAG_UNUSED_LOCAL = '未使用的局部变量 `{}`。' DIAG_UNDEF_GLOBAL = '未定义的全局变量 `{}`。' -DIAG_UNDEF_FIELD = '未定义的 field `{}`。' +DIAG_UNDEF_FIELD = '未定义的属性/字段 `{}`。' DIAG_UNDEF_ENV_CHILD = '未定义的变量 `{}`(重载了 `_ENV` )。' DIAG_UNDEF_FENV_CHILD = '未定义的变量 `{}`(处于模块中)。' DIAG_GLOBAL_IN_NIL_ENV = '不能使用全局变量(`_ENV`被置为了`nil`)。' diff --git a/script/config.lua b/script/config.lua index 298083a4..c9d8e075 100644 --- a/script/config.lua +++ b/script/config.lua @@ -150,6 +150,9 @@ local ConfigTemplate = { intelliSense = { searchDepth = {0, Integer}, }, + telemetry = { + enable = {true, Boolean}, + } } local OtherTemplate = { diff --git a/script/core/completion.lua b/script/core/completion.lua index 436a1689..5db4aa1b 100644 --- a/script/core/completion.lua +++ b/script/core/completion.lua @@ -806,8 +806,9 @@ local function checkUri(ast, text, offset, results) if not collect[info.expect] then collect[info.expect] = { textEdit = { - start = source.start + #source[2], - finish = source.finish - #source[2], + start = source.start + #source[2], + finish = source.finish - #source[2], + newText = info.expect, } } end @@ -835,8 +836,9 @@ local function checkUri(ast, text, offset, results) if not collect[path] then collect[path] = { textEdit = { - start = source.start + #source[2], - finish = source.finish - #source[2], + start = source.start + #source[2], + finish = source.finish - #source[2], + newText = path, } } end diff --git a/script/core/diagnostics/init.lua b/script/core/diagnostics/init.lua index a6b61e12..510b57ea 100644 --- a/script/core/diagnostics/init.lua +++ b/script/core/diagnostics/init.lua @@ -22,8 +22,14 @@ local function check(uri, name, results) end local level = config.config.diagnostics.severity[name] or define.DiagnosticDefaultSeverity[name] - if level == 'Hint' and not files.isOpen(uri) then - return + if not files.isOpen(uri) then + if level == 'Hint' then + return + end + -- TODO + if name == 'undefined-field' then + return + end end local severity = define.DiagnosticSeverity[level] local clock = os.clock() diff --git a/script/core/diagnostics/undefined-field.lua b/script/core/diagnostics/undefined-field.lua index 1b15203c..499b2ffe 100644 --- a/script/core/diagnostics/undefined-field.lua +++ b/script/core/diagnostics/undefined-field.lua @@ -68,7 +68,7 @@ return function (uri, callback) ::CONTINUE:: end end - + if empty then return nil else @@ -93,11 +93,19 @@ return function (uri, callback) if not fields[fieldName] then local message = lang.script('DIAG_UNDEF_FIELD', fieldName) - callback { - start = src.start, - finish = src.finish, - message = message, - } + if src.type == 'getfield' then + callback { + start = src.field.start, + finish = src.field.finish, + message = message, + } + elseif src.type == 'getmethod' then + callback { + start = src.method.start, + finish = src.method.finish, + message = message, + } + end end end guide.eachSourceType(ast.ast, 'getfield', checkUndefinedField); diff --git a/script/core/semantic-tokens.lua b/script/core/semantic-tokens.lua index fdb792da..170bffa8 100644 --- a/script/core/semantic-tokens.lua +++ b/script/core/semantic-tokens.lua @@ -83,7 +83,12 @@ Care['getlocal'] = function (source, results) or source[1] == 'self' then return end - -- 5. 其他 + -- 5. 函数调用 + if source.parent.type == 'call' + and source.parent.node == source then + return + end + -- 6. 其他 results[#results+1] = { start = source.start, finish = source.finish, diff --git a/script/files.lua b/script/files.lua index db33dab1..71981a83 100644 --- a/script/files.lua +++ b/script/files.lua @@ -367,7 +367,7 @@ end ---@param uri string ---@return boolean function m.isLua(uri) - local ext = uri:match '%.([^%.%/%\\]-)$' + local ext = uri:match '%.([^%.%/%\\]+)$' if not ext then return false end diff --git a/script/glob/gitignore.lua b/script/glob/gitignore.lua index f98a2f31..3f942bfb 100644 --- a/script/glob/gitignore.lua +++ b/script/glob/gitignore.lua @@ -19,7 +19,7 @@ end local parser = m.P { 'Main', ['Sp'] = m.S(' \t')^0, - ['Slash'] = m.S('/\\')^1, + ['Slash'] = m.S('/')^1, ['Main'] = m.Ct(m.V'Sp' * m.P'{' * m.V'Pattern' * (',' * expect(m.V'Pattern', 'Miss exp after ","'))^0 * m.P'}') + m.Ct(m.V'Pattern') + m.T'Main Failed' @@ -35,12 +35,20 @@ local parser = m.P { + object('?', m.P'?') + object('[]', m.V'Range') , - ['Char'] = object('char', (1 - m.S',{}[]*?/\\')^1), + ['SimpleChar'] = m.P(1) - m.S',{}[]*?/', + ['EscChar'] = m.P'\\' / '' * m.P(1), + ['Char'] = object('char', m.Cs((m.V'EscChar' + m.V'SimpleChar')^1)), ['FSymbol'] = object('**', m.P'**'), ['Range'] = m.P'[' * m.Ct(m.V'RangeUnit'^0) * m.P']'^-1, ['RangeUnit'] = m.Ct(- m.P']' * m.C(m.P(1)) * (m.P'-' * - m.P']' * m.C(m.P(1)))^-1), } +---@class gitignore +---@field pattern string[] +---@field options table +---@field errors table[] +---@field matcher table +---@field interface function[] local mt = {} mt.__index = mt mt.__name = 'gitignore' @@ -170,7 +178,9 @@ function mt:scan(callback) if type(result) == 'table' then for _, path in ipairs(result) do local filename = path:match '([^/\\]+)[/\\]*$' - if filename then + if filename + and filename ~= '.' + and filename ~= '..' then list[#list+1] = current .. '/' .. filename end end @@ -185,6 +195,7 @@ function mt:__call(path) if self.options.ignoreCase then path = path:lower() end + path = path:gsub('^[/\\]+', '') return self:finishMatch(path) end diff --git a/script/glob/glob.lua b/script/glob/glob.lua index aa8923f3..59fa83a8 100644 --- a/script/glob/glob.lua +++ b/script/glob/glob.lua @@ -19,7 +19,7 @@ end local parser = m.P { 'Main', ['Sp'] = m.S(' \t')^0, - ['Slash'] = m.S('/\\')^1, + ['Slash'] = m.P('/')^1, ['Main'] = m.Ct(m.V'Sp' * m.P'{' * m.V'Pattern' * (',' * expect(m.V'Pattern', 'Miss exp after ","'))^0 * m.P'}') + m.Ct(m.V'Pattern') + m.T'Main Failed' @@ -35,7 +35,9 @@ local parser = m.P { + object('?', m.P'?') + object('[]', m.V'Range') , - ['Char'] = object('char', (1 - m.S',{}[]*?/\\')^1), + ['SimpleChar'] = m.P(1) - m.S',{}[]*?/', + ['EscChar'] = m.P'\\' / '' * m.P(1), + ['Char'] = object('char', m.Cs((m.V'EscChar' + m.V'SimpleChar')^1)), ['FSymbol'] = object('**', m.P'**'), ['RangeWord'] = 1 - m.P']', ['Range'] = m.P'[' * m.Ct(m.V'RangeUnit'^0) * m.P']'^-1, @@ -83,6 +85,7 @@ function mt:__call(path) if self.options.ignoreCase then path = path:lower() end + path = path:gsub('^[/\\]+', '') for _, refused in ipairs(self.refused) do if refused(path) then return false diff --git a/script/provider/provider.lua b/script/provider/provider.lua index 6028e6fe..2fb999e7 100644 --- a/script/provider/provider.lua +++ b/script/provider/provider.lua @@ -652,9 +652,6 @@ proto.on('textDocument/semanticTokens/full', function (params) text = files.getText(uri) end local results = core(uri, 0, #text) - if not results or #results == 0 then - return nil - end return { data = results } @@ -674,9 +671,6 @@ proto.on('textDocument/semanticTokens/range', function (params) local start = define.offset(lines, text, params.range.start) local finish = define.offset(lines, text, params.range['end']) local results = core(uri, start, finish) - if not results or #results == 0 then - return nil - end return { data = results } diff --git a/script/service/init.lua b/script/service/init.lua index eb0bd057..09204c84 100644 --- a/script/service/init.lua +++ b/script/service/init.lua @@ -1,3 +1,4 @@ +require 'service.telemetry' local service = require 'service.service' return service diff --git a/script/service/net.lua b/script/service/net.lua new file mode 100644 index 00000000..9ccd119a --- /dev/null +++ b/script/service/net.lua @@ -0,0 +1,293 @@ +local socket = require "bee.socket" + +local readfds = {} +local writefds = {} +local map = {} + +local function FD_SET(set, fd) + for i = 1, #set do + if fd == set[i] then + return + end + end + set[#set+1] = fd +end + +local function FD_CLR(set, fd) + for i = 1, #set do + if fd == set[i] then + set[i] = set[#set] + set[#set] = nil + return + end + end +end + +local function fd_set_read(fd) + FD_SET(readfds, fd) +end + +local function fd_clr_read(fd) + FD_CLR(readfds, fd) +end + +local function fd_set_write(fd) + FD_SET(writefds, fd) +end + +local function fd_clr_write(fd) + FD_CLR(writefds, fd) +end + +local function on_event(self, name, ...) + local f = self._event[name] + if f then + f(self, ...) + end +end + +local function close(self) + local fd = self._fd + on_event(self, "close") + fd:close() + map[fd] = nil +end + +local stream_mt = {} +local stream = {} +stream_mt.__index = stream +function stream_mt:__newindex(name, func) + if name:sub(1, 3) == "on_" then + self._event[name:sub(4)] = func + end +end +function stream:write(data) + if self.shutdown_w then + return + end + if data == "" then + return + end + if self._writebuf == "" then + fd_set_write(self._fd) + end + self._writebuf = self._writebuf .. data +end +function stream:is_closed() + return self.shutdown_w and self.shutdown_r +end +function stream:close() + if not self.shutdown_r then + self.shutdown_r = true + fd_clr_read(self._fd) + end + if self.shutdown_w or self._writebuf == "" then + self.shutdown_w = true + fd_clr_write(self._fd) + close(self) + end +end +function stream:update(timeout) + local fd = self._fd + local r = {fd} + local w = r + if self._writebuf == "" then + w = nil + end + local rd, wr = socket.select(r, w, timeout or 0) + if rd then + if #rd > 0 then + self:select_r() + end + if #wr > 0 then + self:select_w() + end + end +end +local function close_write(self) + fd_clr_write(self._fd) + if self.shutdown_r then + fd_clr_read(self._fd) + close(self) + end +end +function stream:select_r() + local data = self._fd:recv() + if data == nil then + self:close() + elseif data == false then + else + on_event(self, "data", data) + end +end +function stream:select_w() + local n = self._fd:send(self._writebuf) + if n == nil then + self.shutdown_w = true + close_write(self) + else + self._writebuf = self._writebuf:sub(n + 1) + if self._writebuf == "" then + close_write(self) + end + end +end + +local function accept_stream(fd) + local self = setmetatable({ + _fd = fd, + _event = {}, + _writebuf = "", + shutdown_r = false, + shutdown_w = false, + }, stream_mt) + map[fd] = self + fd_set_read(fd) + return self +end +local function connect_stream(self) + setmetatable(self, stream_mt) + fd_set_read(self._fd) + if self._writebuf ~= "" then + self:select_w() + else + fd_clr_write(self._fd) + end +end + + +local listen_mt = {} +local listen = {} +listen_mt.__index = listen +function listen_mt:__newindex(name, func) + if name:sub(1, 3) == "on_" then + self._event[name:sub(4)] = func + end +end +function listen:is_closed() + return self.shutdown_r +end +function listen:close() + self.shutdown_r = true + fd_clr_read(self._fd) + close(self) +end +function listen:update(timeout) + local fd = self._fd + local r = {fd} + local rd = socket.select(r, nil, timeout or 0) + if rd then + if #rd > 0 then + self:select_r() + end + end +end +function listen:select_r() + local newfd = self._fd:accept() + if newfd:status() then + local news = accept_stream(newfd) + on_event(self, "accept", news) + end +end +local function new_listen(fd) + local s = { + _fd = fd, + _event = {}, + shutdown_r = false, + shutdown_w = true, + } + map[fd] = s + fd_set_read(fd) + return setmetatable(s, listen_mt) +end + +local connect_mt = {} +local connect = {} +connect_mt.__index = connect +function connect_mt:__newindex(name, func) + if name:sub(1, 3) == "on_" then + self._event[name:sub(4)] = func + end +end +function connect:write(data) + if data == "" then + return + end + self._writebuf = self._writebuf .. data +end +function connect:is_closed() + return self.shutdown_w +end +function connect:close() + self.shutdown_w = true + fd_clr_write(self._fd) + close(self) +end +function connect:update(timeout) + local fd = self._fd + local w = {fd} + local rd, wr = socket.select(nil, w, timeout or 0) + if rd then + if #wr > 0 then + self:select_w() + end + end +end +function connect:select_w() + local ok, err = self._fd:status() + if ok then + connect_stream(self) + on_event(self, "connect") + else + on_event(self, "error", err) + self:close() + end +end +local function new_connect(fd) + local s = { + _fd = fd, + _event = {}, + _writebuf = "", + shutdown_r = false, + shutdown_w = false, + } + map[fd] = s + fd_set_write(fd) + return setmetatable(s, connect_mt) +end + +local m = {} + +function m.listen(...) + local fd, err = socket.bind(...) + if not fd then + return fd, err + end + return new_listen(fd) +end + +function m.connect(...) + local fd, err = socket.connect(...) + if not fd then + return fd, err + end + return new_connect(fd) +end + +function m.update(timeout) + local rd, wr = socket.select(readfds, writefds, timeout or 0) + if rd then + for i = 1, #rd do + local fd = rd[i] + local s = map[fd] + s:select_r() + end + for i = 1, #wr do + local fd = wr[i] + local s = map[fd] + s:select_w() + end + end +end + +return m diff --git a/script/service/telemetry.lua b/script/service/telemetry.lua new file mode 100644 index 00000000..d04662b9 --- /dev/null +++ b/script/service/telemetry.lua @@ -0,0 +1,36 @@ +local net = require 'service.net' +local timer = require 'timer' +local config = require 'config' +local client = require 'provider.client' +local nonil = require 'without-check-nil' +local util = require 'utility' + +local tokenPath = (ROOT / 'log' / 'token'):string() +local token = util.loadFile(tokenPath) +if not token then + token = ('%016X'):format(math.random(0, math.maxinteger)) + util.saveFile(tokenPath, token) +end + +local function pushClient(link) + nonil.enable() + local clientName = client.info.clientInfo.name + local clientVersion = client.info.clientInfo.version + nonil.disable() + link:write(string.pack('zzz' + , 'pulse' + , token + , table.concat({clientName, clientVersion}, ' ') + )) +end + +timer.wait(5, function () + timer.loop(60, function () + if not config.config.telemetry.enable then + return + end + local link = net.connect('tcp', '119.45.194.183', 11577) + pushClient(link) + net.update() + end)() +end) diff --git a/script/vm/eachDef.lua b/script/vm/eachDef.lua index 0fcc2df3..7825d2b1 100644 --- a/script/vm/eachDef.lua +++ b/script/vm/eachDef.lua @@ -1,3 +1,4 @@ +---@type vm local vm = require 'vm.vm' local guide = require 'parser.guide' local files = require 'files' diff --git a/script/vm/eachField.lua b/script/vm/eachField.lua index 19ac77e9..292ac39b 100644 --- a/script/vm/eachField.lua +++ b/script/vm/eachField.lua @@ -1,3 +1,4 @@ +---@type vm local vm = require 'vm.vm' local guide = require 'parser.guide' local await = require 'await' diff --git a/script/vm/eachRef.lua b/script/vm/eachRef.lua index 9aa6b783..e9229c38 100644 --- a/script/vm/eachRef.lua +++ b/script/vm/eachRef.lua @@ -1,3 +1,4 @@ +---@type vm local vm = require 'vm.vm' local guide = require 'parser.guide' local util = require 'utility' diff --git a/script/vm/getClass.lua b/script/vm/getClass.lua index d95bab40..1b77171b 100644 --- a/script/vm/getClass.lua +++ b/script/vm/getClass.lua @@ -1,3 +1,4 @@ +---@type vm local vm = require 'vm.vm' local guide = require 'parser.guide' diff --git a/script/vm/getDocs.lua b/script/vm/getDocs.lua index a3f9c714..1c54d593 100644 --- a/script/vm/getDocs.lua +++ b/script/vm/getDocs.lua @@ -1,6 +1,7 @@ local files = require 'files' local util = require 'utility' local guide = require 'parser.guide' +---@type vm local vm = require 'vm.vm' local config = require 'config' diff --git a/script/vm/getGlobals.lua b/script/vm/getGlobals.lua index 26d10a64..37c7f13c 100644 --- a/script/vm/getGlobals.lua +++ b/script/vm/getGlobals.lua @@ -1,4 +1,5 @@ local guide = require 'parser.guide' +---@type vm local vm = require 'vm.vm' local files = require 'files' local util = require 'utility' diff --git a/script/vm/getInfer.lua b/script/vm/getInfer.lua index 45da493f..df1a64e1 100644 --- a/script/vm/getInfer.lua +++ b/script/vm/getInfer.lua @@ -1,3 +1,4 @@ +---@type vm local vm = require 'vm.vm' local guide = require 'parser.guide' local util = require 'utility' diff --git a/script/vm/getLibrary.lua b/script/vm/getLibrary.lua index c2125212..b52f7240 100644 --- a/script/vm/getLibrary.lua +++ b/script/vm/getLibrary.lua @@ -1,3 +1,4 @@ +---@type vm local vm = require 'vm.vm' function vm.getLibraryName(source, deep) diff --git a/script/vm/getLinks.lua b/script/vm/getLinks.lua index 0bb1c6ff..c1690762 100644 --- a/script/vm/getLinks.lua +++ b/script/vm/getLinks.lua @@ -1,4 +1,5 @@ local guide = require 'parser.guide' +---@type vm local vm = require 'vm.vm' local files = require 'files' diff --git a/script/vm/getMeta.lua b/script/vm/getMeta.lua index 67db3d11..b6265dcc 100644 --- a/script/vm/getMeta.lua +++ b/script/vm/getMeta.lua @@ -1,3 +1,4 @@ +---@type vm local vm = require 'vm.vm' local function eachMetaOfArg1(source, callback) diff --git a/script/vm/guideInterface.lua b/script/vm/guideInterface.lua index e646def8..a73067c5 100644 --- a/script/vm/guideInterface.lua +++ b/script/vm/guideInterface.lua @@ -1,3 +1,4 @@ +---@type vm local vm = require 'vm.vm' local files = require 'files' local ws = require 'workspace' diff --git a/test/diagnostics/init.lua b/test/diagnostics/init.lua index 3f3c563c..cfd0f4cb 100644 --- a/test/diagnostics/init.lua +++ b/test/diagnostics/init.lua @@ -847,20 +847,20 @@ local mt2 = {} local v print(v.field1 + 1) print(v.field2 + 1) -print(<!v.field3!> + 1) +print(v.<!field3!> + 1) print(v:method1()) print(v.method2()) -print(<!v:method3!>()) +print(v:<!method3!>()) ---@type Bar local v2 print(v2.field1 + 1) print(v2.field2 + 1) -print(<!v2.field3!> + 1) +print(v2.<!field3!> + 1) print(v2.field4 + 1) print(v2:method1()) print(v2.method2()) -print(<!v2:method3!>()) +print(v2:<!method3!>()) local v3 = {} print(v3.abc) @@ -880,7 +880,7 @@ function Foo:method1() end ---@type Foo local v v:method1() -<!v:method2!>() -- doc.class.name +v:<!method2!>() -- doc.class.name ]] -- checkUndefinedField 通过type找到class,涉及到 class 继承版 @@ -895,7 +895,7 @@ function Bar:method3() end ---@type Bar local v v:method1() -<!v:method2!>() -- doc.class.name +v:<!method2!>() -- doc.class.name v:method3() ]] @@ -904,8 +904,8 @@ TEST [[ ---@class Foo local Foo function Foo:method1() end -<!Foo:method2!>() -- doc.class -<!Foo:method2!>() -- doc.class +Foo:<!method2!>() -- doc.class +Foo:<!method2!>() -- doc.class ]] -- checkUndefinedField 没有@class的不检测 @@ -921,9 +921,9 @@ TEST [[ ---@class Foo local mt function mt:method1() - <!mt.method2!>() -- doc.class + mt.<!method2!>() -- doc.class self.method1() - return <!self.method2!>() -- doc.class.name + return self.<!method2!>() -- doc.class.name end ]] |