diff options
author | CppCXY <812125110@qq.com> | 2022-05-31 20:07:46 +0800 |
---|---|---|
committer | CppCXY <812125110@qq.com> | 2022-05-31 20:07:46 +0800 |
commit | b406413b059843ced4f3dcf4c0c9d041eb78ef05 (patch) | |
tree | b6c9b5a40a025b4fe0011eec9965de9557441aa0 /script | |
parent | 5eef995bdc9e9450f1803fb0f54cdea1025d6e10 (diff) | |
parent | 496b61d601003619aeb6243300b9b3b0f5be944a (diff) | |
download | lua-language-server-b406413b059843ced4f3dcf4c0c9d041eb78ef05.zip |
Merge branch 'master' of https://github.com/sumneko/lua-language-server into HEAD
Diffstat (limited to 'script')
-rw-r--r-- | script/config/config.lua | 12 | ||||
-rw-r--r-- | script/core/code-action.lua | 4 | ||||
-rw-r--r-- | script/core/folding.lua | 12 | ||||
-rw-r--r-- | script/glob/gitignore.lua | 6 | ||||
-rw-r--r-- | script/lclient.lua | 1 | ||||
-rw-r--r-- | script/library.lua | 3 | ||||
-rw-r--r-- | script/proto/define.lua | 1 | ||||
-rw-r--r-- | script/provider/diagnostic.lua | 146 | ||||
-rw-r--r-- | script/provider/formatting.lua | 3 | ||||
-rw-r--r-- | script/provider/provider.lua | 102 | ||||
-rw-r--r-- | script/vm/compiler.lua | 2 | ||||
-rw-r--r-- | script/vm/generic.lua | 3 | ||||
-rw-r--r-- | script/vm/ref.lua | 20 | ||||
-rw-r--r-- | script/workspace/workspace.lua | 19 |
14 files changed, 307 insertions, 27 deletions
diff --git a/script/config/config.lua b/script/config/config.lua index 1dda8c0b..46e80994 100644 --- a/script/config/config.lua +++ b/script/config/config.lua @@ -167,6 +167,9 @@ local Template = { >> util.deepCopy(define.DiagnosticDefaultSeverity), ['Lua.diagnostics.neededFileStatus'] = Type.Hash(Type.String, Type.String) >> util.deepCopy(define.DiagnosticDefaultNeededFileStatus), + ['Lua.diagnostics.disableScheme'] = Type.Hash(Type.String, Type.Boolean, ';') >> { + ['git'] = true, + }, ['Lua.diagnostics.workspaceDelay'] = Type.Integer >> 5, ['Lua.diagnostics.workspaceRate'] = Type.Integer >> 100, ['Lua.diagnostics.libraryFiles'] = Type.String >> 'Opened', @@ -179,6 +182,11 @@ local Template = { ['Lua.workspace.library'] = Type.Hash(Type.String, Type.Boolean, ';'), ['Lua.workspace.checkThirdParty'] = Type.Boolean >> true, ['Lua.workspace.userThirdParty'] = Type.Array(Type.String), + ['Lua.workspace.supportScheme'] = Type.Hash(Type.String, Type.Boolean, ';') >> { + ['file'] = true, + ['untitled'] = true, + ['git'] = true, + }, ['Lua.completion.enable'] = Type.Boolean >> true, ['Lua.completion.callSnippet'] = Type.String >> 'Disable', ['Lua.completion.keywordSnippet'] = Type.String >> 'Replace', @@ -214,6 +222,8 @@ local Template = { >> {}, ['Lua.spell.dict'] = Type.Array(Type.String), ['Lua.telemetry.enable'] = Type.Or(Type.Boolean >> false, Type.Nil) >> nil, + + -- VSCode ['files.associations'] = Type.Hash(Type.String, Type.String), ['files.exclude'] = Type.Hash(Type.String, Type.Boolean), ['editor.semanticHighlighting.enabled'] = Type.Or(Type.Boolean, Type.String), @@ -425,7 +435,7 @@ function m.update(scp, ...) local news = table.pack(...) for i = 1, news.n do - if news[i] then + if type(news[i]) == 'table' then expand(news[i]) end end diff --git a/script/core/code-action.lua b/script/core/code-action.lua index 09b271c6..116fff24 100644 --- a/script/core/code-action.lua +++ b/script/core/code-action.lua @@ -333,6 +333,8 @@ local function solveAwaitInSync(uri, diag, results) end local row = guide.rowColOf(parentFunction.start) local pos = guide.positionOf(row, 0) + local offset = guide.positionToOffset(state, pos + 1) + local space = state.lua:match('[ \t]*', offset) results[#results+1] = { title = lang.script.ACTION_MARK_ASYNC, kind = 'quickfix', @@ -342,7 +344,7 @@ local function solveAwaitInSync(uri, diag, results) { start = pos, finish = pos, - newText = '---@async\n', + newText = space .. '---@async\n', } } } diff --git a/script/core/folding.lua b/script/core/folding.lua index 4f93aed9..0034313a 100644 --- a/script/core/folding.lua +++ b/script/core/folding.lua @@ -66,7 +66,8 @@ local care = { ['repeat'] = function (source, text, results) local start = source.start local finish = source.keyword[#source.keyword] - if text:sub(finish - #'until' + 1, finish) ~= 'until' then + -- must end with 'until' + if #source.keyword ~= 4 then return end local folding = { @@ -143,6 +144,15 @@ local care = { } results[#results+1] = folding end, + ['doc.alias'] = function (source, text, results) + local folding = { + start = source.start, + finish = source.bindGroup[#source.bindGroup].finish, + kind = 'comment', + hideLastLine = true, + } + results[#results+1] = folding + end } ---@async diff --git a/script/glob/gitignore.lua b/script/glob/gitignore.lua index 4dad2747..a6a3df3e 100644 --- a/script/glob/gitignore.lua +++ b/script/glob/gitignore.lua @@ -164,8 +164,9 @@ function mt:getRelativePath(path) end ---@param callback async fun(path: string) +---@param hook? async fun(ev: string, ...) ---@async -function mt:scan(path, callback) +function mt:scan(path, callback, hook) local files = {} if type(callback) ~= 'function' then callback = nil @@ -203,6 +204,9 @@ function mt:scan(path, callback) break end list[#list] = nil + if hook then + hook('scan', current) + end if not self:simpleMatch(current) then check(current) end diff --git a/script/lclient.lua b/script/lclient.lua index ad1fff3d..ce47a816 100644 --- a/script/lclient.lua +++ b/script/lclient.lua @@ -208,6 +208,7 @@ function mt:registerFakers() 'textDocument/publishDiagnostics', 'workspace/configuration', 'workspace/semanticTokens/refresh', + 'workspace/diagnostic/refresh', 'window/workDoneProgress/create', 'window/showMessage', 'window/logMessage', diff --git a/script/library.lua b/script/library.lua index 66c4d364..c7b9ea9a 100644 --- a/script/library.lua +++ b/script/library.lua @@ -477,6 +477,9 @@ local function check3rd(uri) if hasAsked then return end + if not ws.isReady(uri) then + return + end if not config.get(uri, 'Lua.workspace.checkThirdParty') then return end diff --git a/script/proto/define.lua b/script/proto/define.lua index 13ae05e2..52006992 100644 --- a/script/proto/define.lua +++ b/script/proto/define.lua @@ -262,6 +262,7 @@ m.TokenTypes = { ["number"] = 19, ["regexp"] = 20, ["operator"] = 21, + ["decorator"] = 22, } m.BuiltIn = { diff --git a/script/provider/diagnostic.lua b/script/provider/diagnostic.lua index 15b08d49..076a613e 100644 --- a/script/provider/diagnostic.lua +++ b/script/provider/diagnostic.lua @@ -14,6 +14,9 @@ local loading = require 'workspace.loading' local scope = require 'workspace.scope' local time = require 'bee.time' local ltable = require 'linked-table' +local furi = require 'file-uri' +local json = require 'json' +local fw = require 'filewatch' ---@class diagnosticProvider local m = {} @@ -154,6 +157,18 @@ function m.clearCache(uri) m.cache[uri] = false end +function m.clearCacheExcept(uris) + local excepts = {} + for _, uri in ipairs(uris) do + excepts[uri] = true + end + for uri in pairs(m.cache) do + if not excepts[uri] then + m.cache[uri] = false + end + end +end + function m.clearAll() for luri in pairs(m.cache) do m.clear(luri) @@ -193,30 +208,45 @@ local function copyDiagsWithoutSyntax(diags) end ---@async -function m.doDiagnostic(uri, isScopeDiag) +---@param uri uri +---@return boolean +local function isValid(uri) if not config.get(uri, 'Lua.diagnostics.enable') then - return + return false end if files.isLibrary(uri, true) then local status = config.get(uri, 'Lua.diagnostics.libraryFiles') if status == 'Disable' then - return + return false elseif status == 'Opened' then if not files.isOpen(uri) then - return + return false end end end if ws.isIgnored(uri) then local status = config.get(uri, 'Lua.diagnostics.ignoredFiles') if status == 'Disable' then - return + return false elseif status == 'Opened' then if not files.isOpen(uri) then - return + return false end end end + local scheme = furi.split(uri) + local disableScheme = config.get(uri, 'Lua.diagnostics.disableScheme') + if disableScheme[scheme] then + return false + end + return true +end + +---@async +function m.doDiagnostic(uri, isScopeDiag) + if not isValid(uri) then + return + end await.delay() @@ -287,6 +317,42 @@ function m.doDiagnostic(uri, isScopeDiag) pushResult() end +---@async +---@return table|nil result +---@return boolean? unchanged +function m.pullDiagnostic(uri, isScopeDiag) + if not isValid(uri) then + return nil, util.equal(m.cache[uri], nil) + end + + await.delay() + + local state = files.getState(uri) + if not state then + return nil, util.equal(m.cache[uri], nil) + end + + local prog <close> = progress.create(uri, lang.script.WINDOW_DIAGNOSING, 0.5) + prog:setMessage(ws.getRelativePath(uri)) + + local syntax = m.syntaxErrors(uri, state) + local diags = {} + + xpcall(core, log.error, uri, isScopeDiag, function (result) + diags[#diags+1] = buildDiagnostic(uri, result) + end) + + local full = mergeDiags(syntax, diags) + + if util.equal(m.cache[uri], full) then + return full, true + end + + m.cache[uri] = full + + return full +end + function m.refresh(uri) if not ws.isReady(uri) then return @@ -359,7 +425,7 @@ local function askForDisable(uri) end ---@async -function m.awaitDiagnosticsScope(suri) +function m.awaitDiagnosticsScope(suri, callback) local scp = scope.getScope(suri) while loading.count() > 0 do await.sleep(1.0) @@ -393,7 +459,7 @@ function m.awaitDiagnosticsScope(suri) i = i + 1 bar:setMessage(('%d/%d'):format(i, #uris)) bar:setPercentage(i / #uris * 100) - xpcall(m.doDiagnostic, log.error, uri, true) + callback(uri) await.delay() if cancelled then log.info('Break workspace diagnostics') @@ -416,13 +482,65 @@ function m.diagnosticsScope(uri, force) local id = 'diagnosticsScope:' .. scp:getName() await.close(id) await.call(function () ---@async - m.awaitDiagnosticsScope(uri) + m.awaitDiagnosticsScope(uri, function (fileUri) + xpcall(m.doDiagnostic, log.error, fileUri, true) + end) end, id) end +---@async +function m.pullDiagnosticScope(callback) + local processing = 0 + + for _, scp in ipairs(scope.folders) do + if ws.isReady(scp.uri) + and config.get(scp.uri, 'Lua.diagnostics.enable') then + local id = 'diagnosticsScope:' .. scp:getName() + await.close(id) + await.call(function () ---@async + processing = processing + 1 + local _ <close> = util.defer(function () + processing = processing - 1 + end) + + local delay = config.get(scp.uri, 'Lua.diagnostics.workspaceDelay') / 1000 + if delay < 0 then + return + end + print(delay) + await.sleep(math.max(delay, 0.2)) + print('start') + + m.awaitDiagnosticsScope(scp.uri, function (fileUri) + local suc, result, unchanged = xpcall(m.pullDiagnostic, log.error, fileUri, true) + if suc then + callback { + uri = fileUri, + result = result, + unchanged = unchanged, + version = files.getVersion(fileUri), + } + end + end) + end, id) + end + end + + -- sleep for ever + while true do + await.sleep(1.0) + end +end + +function m.refreshClient() + log.debug('Refresh client diagnostics') + proto.request('workspace/diagnostic/refresh', json.null) +end + ws.watch(function (ev, uri) if ev == 'reload' then m.diagnosticsScope(uri) + m.refreshClient() end end) @@ -449,6 +567,16 @@ config.watch(function (uri, key, value, oldValue) if key:find 'Lua.diagnostics' then if value ~= oldValue then m.diagnosticsScope(uri) + m.refreshClient() + end + end +end) + +fw.event(function (ev, path) + if util.stringEndWith(path, '.editorconfig') then + for _, scp in ipairs(ws.folders) do + m.diagnosticsScope(scp.uri) + m.refreshClient() end end end) diff --git a/script/provider/formatting.lua b/script/provider/formatting.lua index 2c8a222e..da31ef65 100644 --- a/script/provider/formatting.lua +++ b/script/provider/formatting.lua @@ -30,9 +30,6 @@ fw.event(function(ev, path) end end end - for _, scp in ipairs(ws.folders) do - diagnostics.diagnosticsScope(scp.uri) - end end end) diff --git a/script/provider/provider.lua b/script/provider/provider.lua index 08b6ca93..af78cd26 100644 --- a/script/provider/provider.lua +++ b/script/provider/provider.lua @@ -236,9 +236,10 @@ m.register 'workspace/didRenameFiles' { m.register 'textDocument/didOpen' { function (params) - local doc = params.textDocument - local scheme = furi.split(doc.uri) - if scheme ~= 'file' then + local doc = params.textDocument + local scheme = furi.split(doc.uri) + local supports = config.get(doc.uri, 'Lua.workspace.supportScheme') + if not supports[scheme] then return end local uri = files.getRealUri(doc.uri) @@ -265,9 +266,10 @@ m.register 'textDocument/didClose' { m.register 'textDocument/didChange' { function (params) - local doc = params.textDocument - local scheme = furi.split(doc.uri) - if scheme ~= 'file' then + local doc = params.textDocument + local scheme = furi.split(doc.uri) + local supports = config.get(doc.uri, 'Lua.workspace.supportScheme') + if not supports[scheme] then return end local changes = params.contentChanges @@ -1210,6 +1212,94 @@ m.register 'inlayHint/resolve' { end } +m.register 'textDocument/diagnostic' { + preview = true, + capability = { + diagnosticProvider = { + identifier = 'identifier', + interFileDependencies = true, + workspaceDiagnostics = false, + } + }, + ---@async + function (params) + local uri = files.getRealUri(params.textDocument.uri) + workspace.awaitReady(uri) + local core = require 'provider.diagnostic' + -- TODO: do some trick + core.refresh(uri) + + return { + kind = 'unchanged', + resultId = uri, + } + + --if not params.previousResultId then + -- core.clearCache(uri) + --end + --local results, unchanged = core.pullDiagnostic(uri, false) + --if unchanged then + -- return { + -- kind = 'unchanged', + -- resultId = uri, + -- } + --else + -- return { + -- kind = 'full', + -- resultId = uri, + -- items = results or {}, + -- } + --end + end +} + +m.register 'workspace/diagnostic' { + --preview = true, + --capability = { + -- diagnosticProvider = { + -- workspaceDiagnostics = false, + -- } + --}, + ---@async + function (params) + local core = require 'provider.diagnostic' + local excepts = {} + for _, id in ipairs(params.previousResultIds) do + excepts[#excepts+1] = id.value + end + core.clearCacheExcept(excepts) + local function convertItem(result) + if result.unchanged then + return { + kind = 'unchanged', + resultId = result.uri, + uri = result.uri, + version = result.version, + } + else + return { + kind = 'full', + resultId = result.uri, + items = result.result or {}, + uri = result.uri, + version = result.version, + } + end + end + core.pullDiagnosticScope(function (result) + proto.notify('$/progress', { + token = params.partialResultToken, + value = { + items = { + convertItem(result) + } + } + }) + end) + return { items = {} } + end +} + local function refreshStatusBar() local valid = config.get(nil, 'Lua.window.statusBar') for _, scp in ipairs(workspace.folders) do diff --git a/script/vm/compiler.lua b/script/vm/compiler.lua index 6c95b5bd..cd2b602d 100644 --- a/script/vm/compiler.lua +++ b/script/vm/compiler.lua @@ -533,7 +533,7 @@ end -- 该函数有副作用,会给source绑定node! local function bindDocs(source) local isParam = source.parent.type == 'funcargs' - or source.parent.type == 'in' + or (source.parent.type == 'in' and source.finish <= source.parent.keys.finish) local docs = source.bindDocs for i = #docs, 1, -1 do local doc = docs[i] diff --git a/script/vm/generic.lua b/script/vm/generic.lua index 6462028e..fafda518 100644 --- a/script/vm/generic.lua +++ b/script/vm/generic.lua @@ -15,6 +15,9 @@ mt.type = 'generic' ---@param resolved? table<string, vm.node> ---@return parser.object | vm.node local function cloneObject(source, resolved) + if not source then + return nil + end if not resolved then return source end diff --git a/script/vm/ref.lua b/script/vm/ref.lua index 545c294a..fbb9d015 100644 --- a/script/vm/ref.lua +++ b/script/vm/ref.lua @@ -279,10 +279,22 @@ local function searchByDef(source, pushResult) defMap[source] = true return defMap end - local defs = vm.getDefs(source) - for _, def in ipairs(defs) do - pushResult(def) - defMap[def] = true + if source.type == 'field' + or source.type == 'method' then + source = source.parent + end + defMap[source] = true + if guide.isSet(source) then + local defs = vm.getDefs(source) + for _, def in ipairs(defs) do + pushResult(def) + end + else + local defs = vm.getDefs(source) + for _, def in ipairs(defs) do + pushResult(def) + defMap[def] = true + end end return defMap end diff --git a/script/workspace/workspace.lua b/script/workspace/workspace.lua index 33f8784d..33252b9d 100644 --- a/script/workspace/workspace.lua +++ b/script/workspace/workspace.lua @@ -13,6 +13,7 @@ local fw = require 'filewatch' local scope = require 'workspace.scope' local loading = require 'workspace.loading' local inspect = require 'inspect' +local lang = require 'language' ---@class workspace local m = {} @@ -46,6 +47,11 @@ end --- 初始化工作区 function m.create(uri) log.info('Workspace create: ', uri) + if uri == furi.encode '/' + or uri == furi.encode(os.getenv 'HOME') then + client.showMessage('Error', lang.script('WORKSPACE_NOT_ALLOWED', furi.decode(uri))) + return + end local path = m.normalize(furi.decode(uri)) fw.watch(path) local scp = scope.createFolder(uri) @@ -283,22 +289,34 @@ function m.awaitPreload(scp) if scp.uri then log.info('Scan files at:', scp:getName()) + local count = 0 ---@async native:scan(furi.decode(scp.uri), function (path) local uri = files.getRealUri(furi.encode(path)) scp:get('cachedUris')[uri] = true ld:loadFile(uri) + end, function () ---@async + count = count + 1 + if count == 100000 then + client.showMessage('Warning', lang.script('WORKSPACE_SCAN_TOO_MUCH', count, furi.decode(scp.uri))) + end end) end for _, libMatcher in ipairs(librarys) do log.info('Scan library at:', libMatcher.uri) + local count = 0 scp:addLink(libMatcher.uri) ---@async libMatcher.matcher:scan(furi.decode(libMatcher.uri), function (path) local uri = files.getRealUri(furi.encode(path)) scp:get('cachedUris')[uri] = true ld:loadFile(uri, libMatcher.uri) + end, function () ---@async + count = count + 1 + if count == 100000 then + client.showMessage('Warning', lang.script('WORKSPACE_SCAN_TOO_MUCH', count, furi.decode(libMatcher.uri))) + end end) scp:gc(fw.watch(furi.decode(libMatcher.uri))) end @@ -353,6 +371,7 @@ function m.normalize(path) if platform.OS == 'Windows' then path = path:gsub('[/\\]+', '\\') :gsub('[/\\]+$', '') + :gsub('^(%a:)$', '%1\\') else path = path:gsub('[/\\]+', '/') :gsub('[/\\]+$', '') |