summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoruhziel <uhziel@gmail.com>2021-01-04 15:59:39 +0800
committerGitHub <noreply@github.com>2021-01-04 15:59:39 +0800
commit525f551abc533b704906fd3a5cb84404fb5cf4de (patch)
tree71e065e94873a86f53bee9886e1c8a39c1b663f8
parentc57556e25cb02e01011272c305854d0f1c106e1c (diff)
parent7a63f98e41305e8deb114164e86a621881a5a2bc (diff)
downloadlua-language-server-525f551abc533b704906fd3a5cb84404fb5cf4de.zip
Merge branch 'master' into doc-type-table
-rw-r--r--changelog.md21
-rw-r--r--main.lua40
-rw-r--r--script/config.lua1
-rw-r--r--script/core/completion.lua218
-rw-r--r--script/core/diagnostics/redundant-parameter.lua56
-rw-r--r--script/core/diagnostics/undefined-field.lua17
-rw-r--r--script/core/hover/table.lua5
-rw-r--r--script/core/rename.lua2
-rw-r--r--script/core/semantic-tokens.lua10
-rw-r--r--script/file-uri.lua6
-rw-r--r--script/files.lua128
-rw-r--r--script/library.lua7
-rw-r--r--script/parser/ast.lua18
-rw-r--r--script/parser/guide.lua158
-rw-r--r--script/parser/luadoc.lua15
-rw-r--r--script/provider/capability.lua12
-rw-r--r--script/provider/completion.lua2
-rw-r--r--script/provider/provider.lua12
-rw-r--r--script/provider/semantic-tokens.lua9
-rw-r--r--script/service/telemetry.lua4
-rw-r--r--script/vm/guideInterface.lua4
-rw-r--r--script/workspace/workspace.lua80
-rw-r--r--test.lua4
-rw-r--r--test/completion/init.lua29
-rw-r--r--test/hover/init.lua4
25 files changed, 680 insertions, 182 deletions
diff --git a/changelog.md b/changelog.md
index 76681f22..6b9d4833 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,6 +1,27 @@
# changelog
+## 1.10.0
+* `NEW` workspace: supports `.dll`(`.so`) in `require`
+* `CHG` supports `~` in command line
+* `CHG` completion: improve workspace words
+* `FIX` [#339](https://github.com/sumneko/lua-language-server/issues/339)
+
+## 1.9.0
+`2020-12-31`
+* `NEW` YEAR! Peace and love!
+* `NEW` specify path of `log` and `meta` by `--logpath=xxx` and `--metapath=XXX` in command line
+* `NEW` completion: worksapce word
+* `NEW` completion: show words in comment
+* `NEW` completion: generate function documentation
+* `CHG` got arg after script name: `lua-language-server.exe main.lua --logpath=D:\log --metapath=D:\meta --develop=false`
+* `FIX` runtime errors
+
+## 1.8.2
+`2020-12-29`
+* `CHG` performance optimization
+
## 1.8.1
+`2020-12-24`
* `FIX` telemetry: connect failed caused not working
## 1.8.0
diff --git a/main.lua b/main.lua
index 806c8e06..9bbd8a1f 100644
--- a/main.lua
+++ b/main.lua
@@ -2,17 +2,51 @@ local currentPath = debug.getinfo(1, 'S').source:sub(2)
local rootPath = currentPath:gsub('[/\\]*[^/\\]-$', '')
loadfile((rootPath == '' and '.' or rootPath) .. '/platform.lua')('script')
local fs = require 'bee.filesystem'
-ROOT = fs.path(rootPath)
-LANG = LANG or 'en-US'
+
+local function expanduser(path)
+ if path:sub(1, 1) == '~' then
+ local home = os.getenv('HOME')
+ if not home then -- has to be Windows
+ home = os.getenv 'USERPROFILE' or (os.getenv 'HOMEDRIVE' .. os.getenv 'HOMEPATH')
+ end
+ return home .. path:sub(2)
+ else
+ return path
+ end
+end
+
+local function loadArgs()
+ for _, v in ipairs(arg) do
+ local key, value = v:match '^%-%-([%w_]+)%=(.+)'
+ if value == 'true' then
+ value = true
+ elseif value == 'false' then
+ value = false
+ elseif tonumber(value) then
+ value = tonumber(value)
+ elseif value:sub(1, 1) == '"' and value:sub(-1, -1) == '"' then
+ value = value:sub(2, -2)
+ end
+ _G[key:upper()] = value
+ end
+end
+
+loadArgs()
+
+ROOT = fs.path(expanduser(rootPath))
+LOGPATH = LOGPATH and expanduser(LOGPATH) or (ROOT:string() .. '/log')
+METAPATH = METAPATH and expanduser(METAPATH) or (ROOT:string() .. '/meta')
debug.setcstacklimit(200)
collectgarbage('generational', 10, 100)
--collectgarbage('incremental', 120, 120, 0)
log = require 'log'
-log.init(ROOT, ROOT / 'log' / 'service.log')
+log.init(ROOT, fs.path(LOGPATH) / 'service.log')
log.info('Lua Lsp startup, root: ', ROOT)
log.debug('ROOT:', ROOT:string())
+log.debug('LOGPATH:', LOGPATH)
+log.debug('METAPATH:', METAPATH)
require 'tracy'
diff --git a/script/config.lua b/script/config.lua
index eecd8ffa..b6ae4767 100644
--- a/script/config.lua
+++ b/script/config.lua
@@ -137,6 +137,7 @@ local ConfigTemplate = {
callSnippet = {'Disable', String},
keywordSnippet = {'Replace', String},
displayContext = {6, Integer},
+ workspaceWord = {true, Boolean},
},
signatureHelp = {
enable = {true, Boolean},
diff --git a/script/core/completion.lua b/script/core/completion.lua
index b1610ff0..ba848272 100644
--- a/script/core/completion.lua
+++ b/script/core/completion.lua
@@ -592,7 +592,8 @@ local function checkTableField(ast, word, start, results)
end)
end
-local function checkCommon(word, text, offset, results)
+local function checkCommon(ast, word, text, offset, results)
+ local myUri = ast.uri
local used = {}
for _, result in ipairs(results) do
used[result.label] = true
@@ -600,14 +601,56 @@ local function checkCommon(word, text, offset, results)
for _, data in ipairs(keyWordMap) do
used[data[1]] = true
end
- for str, pos in text:gmatch '([%a_][%w_]*)()' do
- if not used[str] and pos - 1 ~= offset then
- used[str] = true
- if matchKey(word, str) then
- results[#results+1] = {
- label = str,
- kind = define.CompletionItemKind.Text,
- }
+ if config.config.completion.workspaceWord then
+ for uri in files.eachFile() do
+ local cache = files.getCache(uri)
+ if not cache.commonWords then
+ cache.commonWords = {}
+ local mark = {}
+ for str in files.getText(uri):gmatch '([%a_][%w_]*)' do
+ if not mark[str] then
+ mark[str] = true
+ cache.commonWords[#cache.commonWords+1] = str
+ end
+ end
+ end
+ for _, str in ipairs(cache.commonWords) do
+ if not used[str]
+ and (str ~= word or not files.eq(myUri, uri)) then
+ used[str] = true
+ if matchKey(word, str) then
+ results[#results+1] = {
+ label = str,
+ kind = define.CompletionItemKind.Text,
+ }
+ end
+ end
+ end
+ end
+ for uri in files.eachDll() do
+ local words = files.getDllWords(uri) or {}
+ for _, str in ipairs(words) do
+ if not used[str] and str ~= word then
+ used[str] = true
+ if matchKey(word, str) then
+ results[#results+1] = {
+ label = str,
+ kind = define.CompletionItemKind.Text,
+ }
+ end
+ end
+ end
+ end
+ else
+ for str, pos in text:gmatch '([%a_][%w_]*)()' do
+ if not used[str] and pos - 1 ~= offset then
+ used[str] = true
+ if matchKey(word, str) then
+ results[#results+1] = {
+ label = str,
+ kind = define.CompletionItemKind.Text,
+ }
+ end
end
end
end
@@ -821,6 +864,27 @@ local function checkUri(ast, text, offset, results)
end
::CONTINUE::
end
+ for uri in files.eachDll() do
+ local opens = files.getDllOpens(uri) or {}
+ local path = workspace.getRelativePath(uri)
+ for _, open in ipairs(opens) do
+ if matchKey(literal, open) then
+ if not collect[open] then
+ collect[open] = {
+ textEdit = {
+ start = source.start + #source[2],
+ finish = source.finish - #source[2],
+ newText = open,
+ }
+ }
+ end
+ collect[open][#collect[open]+1] = ([=[* [%s](%s)]=]):format(
+ path,
+ uri
+ )
+ end
+ end
+ end
elseif libName == 'dofile'
or libName == 'loadfile' then
for uri in files.eachFile() do
@@ -970,6 +1034,9 @@ local function checkTypingEnum(ast, text, offset, infers, str, results)
end
local myResults = {}
mergeEnums(myResults, enums, str)
+ table.sort(myResults, function (a, b)
+ return a.label < b.label
+ end)
for _, res in ipairs(myResults) do
results[#results+1] = res
end
@@ -1119,7 +1186,7 @@ local function tryWord(ast, text, offset, results)
end
end
if not hasSpace then
- checkCommon(word, text, offset, results)
+ checkCommon(ast, word, text, offset, results)
end
end
end
@@ -1266,6 +1333,15 @@ local function getComment(ast, offset)
return nil
end
+local function getLuaDoc(ast, offset)
+ for _, doc in ipairs(ast.ast.docs) do
+ if offset >= doc.start and offset <= doc.range then
+ return doc
+ end
+ end
+ return nil
+end
+
local function tryLuaDocCate(line, results)
local word = line:sub(3)
for _, docType in ipairs {
@@ -1347,6 +1423,7 @@ local function tryLuaDocBySource(ast, offset, source, results)
end
end
end
+ return true
elseif source.type == 'doc.type.name' then
for _, doc in ipairs(vm.getDocTypes '*') do
if (doc.type == 'doc.class.name' or doc.type == 'doc.alias.name')
@@ -1358,6 +1435,7 @@ local function tryLuaDocBySource(ast, offset, source, results)
}
end
end
+ return true
elseif source.type == 'doc.param.name' then
local funcs = {}
guide.eachSourceBetween(ast.ast, offset, math.huge, function (src)
@@ -1380,7 +1458,9 @@ local function tryLuaDocBySource(ast, offset, source, results)
}
end
end
+ return true
end
+ return false
end
local function tryLuaDocByErr(ast, offset, err, docState, results)
@@ -1446,40 +1526,121 @@ local function tryLuaDocByErr(ast, offset, err, docState, results)
end
end
-local function tryLuaDocFeatures(line, ast, comm, offset, results)
+local function buildLuaDocOfFunction(func)
+ local index = 1
+ local buf = {}
+ buf[#buf+1] = '${1:comment}'
+ local args = {}
+ local returns = {}
+ if func.args then
+ for _, arg in ipairs(func.args) do
+ args[#args+1] = vm.getInferType(arg)
+ end
+ end
+ if func.returns then
+ for _, rtns in ipairs(func.returns) do
+ for n = 1, #rtns do
+ if not returns[n] then
+ returns[n] = vm.getInferType(rtns[n])
+ end
+ end
+ end
+ end
+ for n, arg in ipairs(args) do
+ index = index + 1
+ buf[#buf+1] = ('---@param %s ${%d:%s}'):format(
+ func.args[n][1],
+ index,
+ arg
+ )
+ end
+ for _, rtn in ipairs(returns) do
+ index = index + 1
+ buf[#buf+1] = ('---@return ${%d:%s}'):format(
+ index,
+ rtn
+ )
+ end
+ local insertText = table.concat(buf, '\n')
+ return insertText
end
-local function tryLuaDoc(ast, text, offset, results)
- local comm = getComment(ast, offset)
- local line = text:sub(comm.start, offset)
- if not line then
+local function tryLuaDocOfFunction(doc, results)
+ if not doc.bindSources then
return
end
- if line:sub(1, 2) ~= '-@' then
- return
+ local func
+ for _, source in ipairs(doc.bindSources) do
+ if source.type == 'function' then
+ func = source
+ break
+ end
end
- -- 尝试 ---@$
- local cate = line:match('%a*', 3)
- if #cate + 2 >= #line then
- tryLuaDocCate(line, results)
+ if not func then
return
end
- -- 尝试一些其他特征
- if tryLuaDocFeatures(line, ast, comm, offset, results) then
+ for _, otherDoc in ipairs(doc.bindGroup) do
+ if otherDoc.type == 'doc.param'
+ or otherDoc.type == 'doc.return' then
+ return
+ end
+ end
+ local insertText = buildLuaDocOfFunction(func)
+ results[#results+1] = {
+ label = '@param;@return',
+ kind = define.CompletionItemKind.Snippet,
+ insertTextFormat = 2,
+ filterText = '---',
+ insertText = insertText
+ }
+end
+
+local function tryLuaDoc(ast, text, offset, results)
+ local doc = getLuaDoc(ast, offset)
+ if not doc then
return
end
+ if doc.type == 'doc.comment' then
+ local line = text:sub(doc.start, doc.range)
+ -- 尝试 ---$
+ if line == '-' then
+ tryLuaDocOfFunction(doc, results)
+ return
+ end
+ -- 尝试 ---@$
+ local cate = line:match('^-@(%a*)$')
+ if cate then
+ tryLuaDocCate(line, results)
+ return
+ end
+ end
-- 根据输入中的source来补全
local source = getLuaDocByContain(ast, offset)
if source then
- tryLuaDocBySource(ast, offset, source, results)
- return
+ local suc = tryLuaDocBySource(ast, offset, source, results)
+ if suc then
+ return
+ end
end
-- 根据附近的错误消息来补全
- local err, doc = getLuaDocByErr(ast, text, comm.start, offset)
+ local err, expectDoc = getLuaDocByErr(ast, text, doc.start, offset)
if err then
- tryLuaDocByErr(ast, offset, err, doc, results)
+ tryLuaDocByErr(ast, offset, err, expectDoc, results)
+ return
+ end
+end
+
+local function tryComment(ast, text, offset, results)
+ local word = findWord(text, offset)
+ local doc = getLuaDoc(ast, offset)
+ local line = text:sub(doc.start, offset)
+ if not word then
+ return
+ end
+ if doc and doc.type ~= 'doc.comment' then
return
end
+ checkCommon(ast, word, text, offset, results)
end
local function completion(uri, offset)
@@ -1490,6 +1651,7 @@ local function completion(uri, offset)
if ast then
if getComment(ast, offset) then
tryLuaDoc(ast, text, offset, results)
+ tryComment(ast, text, offset, results)
else
trySpecial(ast, text, offset, results)
tryWord(ast, text, offset, results)
@@ -1500,7 +1662,7 @@ local function completion(uri, offset)
else
local word = findWord(text, offset)
if word then
- checkCommon(word, text, offset, results)
+ checkCommon(ast, word, text, offset, results)
end
end
diff --git a/script/core/diagnostics/redundant-parameter.lua b/script/core/diagnostics/redundant-parameter.lua
index ac52ab2a..f7b0ae75 100644
--- a/script/core/diagnostics/redundant-parameter.lua
+++ b/script/core/diagnostics/redundant-parameter.lua
@@ -48,12 +48,41 @@ local function countOverLoadArgs(source, doc)
return result
end
+local function getFuncArgs(func)
+ local funcArgs
+ local defs = vm.getDefs(func)
+ for _, def in ipairs(defs) do
+ if def.value then
+ def = def.value
+ end
+ if def.type == 'function' then
+ local args = countFuncArgs(def)
+ if not funcArgs or args > funcArgs then
+ funcArgs = args
+ end
+ if def.bindDocs then
+ for _, doc in ipairs(def.bindDocs) do
+ if doc.type == 'doc.overload' then
+ args = countOverLoadArgs(def, doc)
+ if not funcArgs or args > funcArgs then
+ funcArgs = args
+ end
+ end
+ end
+ end
+ end
+ end
+ return funcArgs
+end
+
return function (uri, callback)
local ast = files.getAst(uri)
if not ast then
return
end
+ local cache = vm.getCache 'redundant-parameter'
+
guide.eachSourceType(ast.ast, 'call', function (source)
local callArgs = countCallArgs(source)
if callArgs == 0 then
@@ -61,27 +90,12 @@ return function (uri, callback)
end
local func = source.node
- local funcArgs
- local defs = vm.getDefs(func)
- for _, def in ipairs(defs) do
- if def.value then
- def = def.value
- end
- if def.type == 'function' then
- local args = countFuncArgs(def)
- if not funcArgs or args > funcArgs then
- funcArgs = args
- end
- if def.bindDocs then
- for _, doc in ipairs(def.bindDocs) do
- if doc.type == 'doc.overload' then
- args = countOverLoadArgs(def, doc)
- if not funcArgs or args > funcArgs then
- funcArgs = args
- end
- end
- end
- end
+ local funcArgs = cache[func]
+ if funcArgs == nil then
+ funcArgs = getFuncArgs(func) or false
+ local refs = vm.getRefs(func, 0)
+ for _, ref in ipairs(refs) do
+ cache[ref] = funcArgs
end
end
diff --git a/script/core/diagnostics/undefined-field.lua b/script/core/diagnostics/undefined-field.lua
index 31bd9008..ffa70364 100644
--- a/script/core/diagnostics/undefined-field.lua
+++ b/script/core/diagnostics/undefined-field.lua
@@ -11,10 +11,19 @@ return function (uri, callback)
return
end
+ local cache = vm.getCache 'undefined-field'
+
local function getAllDocClassFromInfer(src)
- tracy.ZoneBeginN('undefined-field getInfers')
- local infers = vm.getInfers(src, 0)
- tracy.ZoneEnd()
+ local infers = cache[src]
+ if cache[src] == nil then
+ tracy.ZoneBeginN('undefined-field getInfers')
+ infers = vm.getInfers(src, 0) or false
+ local refs = vm.getRefs(src, 0)
+ for _, ref in ipairs(refs) do
+ cache[ref] = infers
+ end
+ tracy.ZoneEnd()
+ end
if not infers then
return nil
@@ -55,7 +64,9 @@ return function (uri, callback)
local fields = {}
local empty = true
for _, docClass in ipairs(allDocClass) do
+ tracy.ZoneBeginN('undefined-field getDefFields')
local refs = vm.getDefFields(docClass)
+ tracy.ZoneEnd()
for _, ref in ipairs(refs) do
local name = vm.getKeyName(ref)
diff --git a/script/core/hover/table.lua b/script/core/hover/table.lua
index 9fd79a25..58e64951 100644
--- a/script/core/hover/table.lua
+++ b/script/core/hover/table.lua
@@ -31,9 +31,10 @@ local function getKey(src)
end
local function getFieldFull(src)
- local tp = vm.getInferType(src)
+ local value = guide.getObjectValue(src) or src
+ local tp = vm.getInferType(value, 0)
--local class = vm.getClass(src)
- local literal = vm.getInferLiteral(src)
+ local literal = vm.getInferLiteral(value)
if type(literal) == 'string' and #literal >= 50 then
literal = literal:sub(1, 47) .. '...'
end
diff --git a/script/core/rename.lua b/script/core/rename.lua
index b823cb86..3f73c338 100644
--- a/script/core/rename.lua
+++ b/script/core/rename.lua
@@ -292,7 +292,7 @@ local function ofField(source, newname, callback)
else
node = source.node
end
- for _, src in ipairs(vm.getFields(node, 0)) do
+ for _, src in ipairs(vm.getFields(node, 5)) do
ofFieldThen(key, src, newname, callback)
end
end
diff --git a/script/core/semantic-tokens.lua b/script/core/semantic-tokens.lua
index 37eabda7..1c59d80d 100644
--- a/script/core/semantic-tokens.lua
+++ b/script/core/semantic-tokens.lua
@@ -187,6 +187,16 @@ return function (uri, start, finish)
end
end)
+ for _, comm in ipairs(ast.comms) do
+ if comm.semantic then
+ results[#results+1] = {
+ start = comm.start,
+ finish = comm.finish,
+ type = define.TokenTypes.comment,
+ }
+ end
+ end
+
table.sort(results, function (a, b)
return a.start < b.start
end)
diff --git a/script/file-uri.lua b/script/file-uri.lua
index ba44f2e7..d1c495b4 100644
--- a/script/file-uri.lua
+++ b/script/file-uri.lua
@@ -1,5 +1,7 @@
local platform = require 'bee.platform'
+---@class uri: string
+
local escPatt = '[^%w%-%.%_%~%/]'
local function esc(c)
@@ -20,7 +22,7 @@ local m = {}
--- path -> uri
---@param path string
----@return string uri
+---@return uri uri
function m.encode(path)
local authority = ''
if platform.OS == 'Windows' then
@@ -62,7 +64,7 @@ end
-- file://server/share/some/path --> \\server\share\some\path
--- uri -> path
----@param uri string
+---@param uri uri
---@return string path
function m.decode(uri)
local scheme, authority, path = uri:match('([^:]*):?/?/?([^/]*)(.*)')
diff --git a/script/files.lua b/script/files.lua
index 9ffcd2a1..22ffab95 100644
--- a/script/files.lua
+++ b/script/files.lua
@@ -10,19 +10,20 @@ local timer = require 'timer'
local m = {}
-m.openMap = {}
-m.libraryMap = {}
-m.fileMap = {}
-m.watchList = {}
-m.notifyCache = {}
-m.assocVersion = -1
-m.assocMatcher = nil
+m.openMap = {}
+m.libraryMap = {}
+m.fileMap = {}
+m.dllMap = {}
+m.watchList = {}
+m.notifyCache = {}
+m.assocVersion = -1
+m.assocMatcher = nil
m.globalVersion = 0
m.linesMap = setmetatable({}, { __mode = 'v' })
m.astMap = setmetatable({}, { __mode = 'v' })
--- 打开文件
----@param uri string
+---@param uri uri
function m.open(uri)
local originUri = uri
if platform.OS == 'Windows' then
@@ -33,7 +34,7 @@ function m.open(uri)
end
--- 关闭文件
----@param uri string
+---@param uri uri
function m.close(uri)
local originUri = uri
if platform.OS == 'Windows' then
@@ -44,7 +45,7 @@ function m.close(uri)
end
--- 是否打开
----@param uri string
+---@param uri uri
---@return boolean
function m.isOpen(uri)
if platform.OS == 'Windows' then
@@ -98,7 +99,7 @@ function m.asKey(uri)
end
--- 设置文件文本
----@param uri string
+---@param uri uri
---@param text string
function m.setText(uri, text)
if not text then
@@ -147,7 +148,7 @@ function m.getVersion(uri)
end
--- 获取文件文本
----@param uri string
+---@param uri uri
---@return string text
function m.getText(uri)
if platform.OS == 'Windows' then
@@ -161,7 +162,7 @@ function m.getText(uri)
end
--- 移除文件
----@param uri string
+---@param uri uri
function m.remove(uri)
local originUri = uri
if platform.OS == 'Windows' then
@@ -218,6 +219,16 @@ function m.eachFile()
return pairs(map)
end
+--- Pairs dll files
+---@return function
+function m.eachDll()
+ local map = {}
+ for uri, file in pairs(m.dllMap) do
+ map[uri] = file
+ end
+ return pairs(map)
+end
+
function m.compileAst(uri, text)
if not m.isOpen(uri) and #text >= config.config.workspace.preloadFileSize * 1000 then
if not m.notifyCache['preloadFileSize'] then
@@ -267,7 +278,7 @@ function m.compileAst(uri, text)
end
--- 获取文件语法树
----@param uri string
+---@param uri uri
---@return table ast
function m.getAst(uri)
if platform.OS == 'Windows' then
@@ -290,7 +301,7 @@ function m.getAst(uri)
end
--- 获取文件行信息
----@param uri string
+---@param uri uri
---@return table lines
function m.getLines(uri)
if platform.OS == 'Windows' then
@@ -313,7 +324,7 @@ function m.getOriginUri(uri)
if platform.OS == 'Windows' then
uri = uri:lower()
end
- local file = m.fileMap[uri]
+ local file = m.fileMap[uri] or m.dllMap[uri]
if not file then
return nil
end
@@ -369,7 +380,7 @@ function m.getAssoc()
end
--- 判断是否是Lua文件
----@param uri string
+---@param uri uri
---@return boolean
function m.isLua(uri)
local ext = uri:match '%.([^%.%/%\\]+)$'
@@ -384,6 +395,89 @@ function m.isLua(uri)
return matcher(path)
end
+--- Does the uri look like a `Dynamic link library` ?
+---@param uri uri
+---@return boolean
+function m.isDll(uri)
+ local ext = uri:match '%.([^%.%/%\\]+)$'
+ if not ext then
+ return false
+ end
+ if platform.OS == 'Windows' then
+ if m.eq(ext, 'dll') then
+ return true
+ end
+ else
+ if m.eq(ext, 'so') then
+ return true
+ end
+ end
+ return false
+end
+
+--- Save dll, makes opens and words, discard content
+---@param uri uri
+---@param content string
+function m.saveDll(uri, content)
+ if not content then
+ return
+ end
+ local luri = uri
+ if platform.OS == 'Windows' then
+ luri = uri:lower()
+ end
+ local file = {
+ uri = uri,
+ opens = {},
+ words = {},
+ }
+ for word in content:gmatch 'luaopen_([%w_]+)' do
+ file.opens[#file.opens+1] = word:gsub('_', '.')
+ end
+ if #file.opens == 0 then
+ return
+ end
+ local mark = {}
+ for word in content:gmatch '(%a[%w_]+)\0' do
+ if word:sub(1, 3) ~= 'lua' then
+ if not mark[word] then
+ mark[word] = true
+ file.words[#file.words+1] = word
+ end
+ end
+ end
+
+ m.dllMap[luri] = file
+end
+
+---
+---@param uri uri
+---@return string[]|nil
+function m.getDllOpens(uri)
+ if platform.OS == 'Windows' then
+ uri = uri:lower()
+ end
+ local file = m.dllMap[uri]
+ if not file then
+ return nil
+ end
+ return file.opens
+end
+
+---
+---@param uri uri
+---@return string[]|nil
+function m.getDllWords(uri)
+ if platform.OS == 'Windows' then
+ uri = uri:lower()
+ end
+ local file = m.dllMap[uri]
+ if not file then
+ return nil
+ end
+ return file.words
+end
+
--- 注册事件
function m.watch(callback)
m.watchList[#m.watchList+1] = callback
diff --git a/script/library.lua b/script/library.lua
index a49bef85..09b14d25 100644
--- a/script/library.lua
+++ b/script/library.lua
@@ -164,13 +164,10 @@ end
local function compileMetaDoc()
local langID = lang.id
local version = config.config.runtime.version
- local metapath = ROOT / 'meta' / config.config.runtime.meta:gsub('%$%{(.-)%}', {
+ local metapath = fs.path(METAPATH) / config.config.runtime.meta:gsub('%$%{(.-)%}', {
version = version,
language = langID,
})
- if fs.exists(metapath) then
- --return
- end
local metaLang = loadMetaLocale('en-US')
if langID ~= 'en-US' then
@@ -180,7 +177,7 @@ local function compileMetaDoc()
m.metaPath = metapath:string()
m.metaPaths = {}
- fs.create_directory(metapath)
+ fs.create_directories(metapath)
local templateDir = ROOT / 'meta' / 'template'
for fullpath in templateDir:list_directory() do
local filename = fullpath:filename()
diff --git a/script/parser/ast.lua b/script/parser/ast.lua
index 127bb08c..68fd59d7 100644
--- a/script/parser/ast.lua
+++ b/script/parser/ast.lua
@@ -333,10 +333,11 @@ local Defs = {
}
}
end
- return {
- type = 'nonstandardSymbol.comment',
- start = start1,
- finish = finish2 - 1,
+ PushComment {
+ start = start1,
+ finish = finish2 - 1,
+ semantic = true,
+ text = '',
}
end,
CCommentPrefix = function (start, finish, commentFinish)
@@ -356,10 +357,11 @@ local Defs = {
}
}
end
- return {
- type = 'nonstandardSymbol.comment',
- start = start,
- finish = commentFinish - 1,
+ PushComment {
+ start = start,
+ finish = commentFinish - 1,
+ semantic = true,
+ text = '',
}
end,
String = function (start, quote, str, finish)
diff --git a/script/parser/guide.lua b/script/parser/guide.lua
index 7a5be591..fed3577f 100644
--- a/script/parser/guide.lua
+++ b/script/parser/guide.lua
@@ -27,6 +27,8 @@ local function logWarn(...)
log.warn(...)
end
+---@class guide
+---@field debugMode boolean
local m = {}
m.ANY = {"<ANY>"}
@@ -1236,6 +1238,7 @@ function m.status(parentStatus, interface, deep)
searchDeep= parentStatus and parentStatus.searchDeep or deep or -999,
interface = parentStatus and parentStatus.interface or {},
deep = parentStatus and parentStatus.deep,
+ clock = parentStatus and parentStatus.clock or osClock(),
results = {},
}
if interface then
@@ -1365,6 +1368,10 @@ function m.getCallValue(source)
else
return
end
+ if call.node.special == 'pcall'
+ or call.node.special == 'xpcall' then
+ return call.args[1], call.args, index - 1
+ end
return call.node, call.args, index
end
@@ -1478,6 +1485,9 @@ function m.checkSameSimpleInValueOfSetMetaTable(status, func, start, pushQueue)
end
local call = func.parent
local args = call.args
+ if not args then
+ return
+ end
local obj = args[1]
local mt = args[2]
if obj then
@@ -1653,6 +1663,20 @@ function m.checkSameSimpleOfRefByDocSource(status, obj, start, pushQueue, mode)
end
end
+local function getArrayLevel(obj)
+ local level = 0
+ while true do
+ local parent = obj.parent
+ if parent.type == 'doc.type.array' then
+ level = level + 1
+ else
+ break
+ end
+ obj = parent
+ end
+ return level
+end
+
function m.checkSameSimpleByDoc(status, obj, start, pushQueue, mode)
if obj.type == 'doc.class.name'
or obj.type == 'doc.class' then
@@ -1705,7 +1729,7 @@ function m.checkSameSimpleByDoc(status, obj, start, pushQueue, mode)
if not parentDocTypeTable then
local state = m.getDocState(obj)
if state.type == 'doc.type' and mode == 'ref' then
- m.checkSameSimpleOfRefByDocSource(status, state, start, pushQueue, mode)
+ m.checkSameSimpleOfRefByDocSource(status, state, start - getArrayLevel(obj), pushQueue, mode)
end
end
return true
@@ -1833,6 +1857,7 @@ function m.searchSameFieldsCrossMethod(status, ref, start, pushQueue)
end
local function checkSameSimpleAndMergeFunctionReturnsByDoc(status, results, source, index, args)
+ source = m.getObjectValue(source) or source
if not source or source.type ~= 'function' then
return
end
@@ -1922,13 +1947,13 @@ function m.checkSameSimpleInCall(status, ref, start, pushQueue, mode)
return
end
status.share.crossCallCount = status.share.crossCallCount or 0
- if status.share.crossCallCount >= 5 then
- return
- end
- status.share.crossCallCount = status.share.crossCallCount + 1
-- 检查赋值是 semetatable() 的情况
m.checkSameSimpleInValueOfSetMetaTable(status, func, start, pushQueue)
-- 检查赋值是 func() 的情况
+ if status.share.crossCallCount >= 2 then
+ return
+ end
+ status.share.crossCallCount = status.share.crossCallCount + 1
local objs = m.checkSameSimpleInCallInSameFile(status, func, args, index)
if status.interface.call then
local cobjs = status.interface.call(func, args, index)
@@ -1941,15 +1966,22 @@ function m.checkSameSimpleInCall(status, ref, start, pushQueue, mode)
end
end
m.cleanResults(objs)
- local newStatus = m.status(status)
+ local mark = {}
for _, obj in ipairs(objs) do
+ if mark[obj] then
+ goto CONTINUE
+ end
+ local newStatus = m.status(status)
m.searchRefs(newStatus, obj, mode)
pushQueue(obj, start, true)
+ mark[obj] = true
+ for _, obj in ipairs(newStatus.results) do
+ pushQueue(obj, start, true)
+ mark[obj] = true
+ end
+ ::CONTINUE::
end
status.share.crossCallCount = status.share.crossCallCount - 1
- for _, obj in ipairs(newStatus.results) do
- pushQueue(obj, start, true)
- end
end
local function searchRawset(ref, results)
@@ -2320,6 +2352,7 @@ function m.pushResult(status, mode, ref, simple)
results[#results+1] = ref
elseif ref.type == 'doc.type.function'
or ref.type == 'doc.class.name'
+ or ref.type == 'doc.alias.name'
or ref.type == 'doc.field' then
results[#results+1] = ref
end
@@ -2362,6 +2395,7 @@ function m.pushResult(status, mode, ref, simple)
end
elseif ref.type == 'doc.type.function'
or ref.type == 'doc.class.name'
+ or ref.type == 'doc.alias.name'
or ref.type == 'doc.field' then
results[#results+1] = ref
end
@@ -2369,6 +2403,7 @@ function m.pushResult(status, mode, ref, simple)
results[#results+1] = ref
end
if m.isLiteral(ref)
+ and ref.parent
and ref.parent.type == 'callargs'
and ref ~= simple.node then
results[#results+1] = ref
@@ -2392,18 +2427,12 @@ function m.pushResult(status, mode, ref, simple)
elseif ref.type == 'setglobal'
or ref.type == 'getglobal' then
results[#results+1] = ref
- elseif ref.type == 'function' then
- results[#results+1] = ref
- elseif ref.type == 'table' then
- results[#results+1] = ref
elseif ref.type == 'call' then
if ref.node.special == 'rawset'
or ref.node.special == 'rawget' then
results[#results+1] = ref
end
- elseif ref.type == 'doc.type.function'
- or ref.type == 'doc.class.name'
- or ref.type == 'doc.field' then
+ elseif ref.type == 'doc.field' then
results[#results+1] = ref
end
elseif mode == 'deffield' then
@@ -2417,17 +2446,11 @@ function m.pushResult(status, mode, ref, simple)
results[#results+1] = ref
elseif ref.type == 'setglobal' then
results[#results+1] = ref
- elseif ref.type == 'function' then
- results[#results+1] = ref
- elseif ref.type == 'table' then
- results[#results+1] = ref
elseif ref.type == 'call' then
if ref.node.special == 'rawset' then
results[#results+1] = ref
end
- elseif ref.type == 'doc.type.function'
- or ref.type == 'doc.class.name'
- or ref.type == 'doc.field' then
+ elseif ref.type == 'doc.field' then
results[#results+1] = ref
end
end
@@ -2438,10 +2461,6 @@ function m.checkSameSimpleName(ref, sm)
return true
end
- if sm == m.ANY_DEF and m.isSet(ref) then
- return true
- end
-
if m.getSimpleName(ref) == sm then
return true
end
@@ -2567,6 +2586,9 @@ function m.searchSameFields(status, simple, mode)
local obj = queues[queueLen]
local start = starts[queueLen]
local force = forces[queueLen]
+ queues[queueLen] = nil
+ starts[queueLen] = nil
+ forces[queueLen] = nil
queueLen = queueLen - 1
local lock = locks[start]
if not lock then
@@ -2577,6 +2599,18 @@ function m.searchSameFields(status, simple, mode)
lock[obj] = true
max = max + 1
status.share.count = status.share.count + 1
+ if status.share.count % 10000 == 0 then
+ if TEST then
+ print('####', status.share.count, osClock() - status.clock)
+ end
+ if status.interface and status.interface.pulse then
+ status.interface.pulse()
+ end
+ end
+ --if status.share.count >= 100000 then
+ -- logWarn('Count too large!')
+ -- break
+ --end
m.checkSameSimple(status, simple, obj, start, force, mode, pushQueue)
if max >= 10000 then
logWarn('Queue too large!')
@@ -2584,7 +2618,7 @@ function m.searchSameFields(status, simple, mode)
end
end
end
- deallocQueue(queues, starts, forces)
+ --deallocQueue(queues, starts, forces)
end
function m.getCallerInSameFile(status, func)
@@ -2741,12 +2775,9 @@ end
--end
function m.getRefCache(status, obj, mode)
- local cache, globalCache
- if status.depth == 1
- and status.deep then
- globalCache = status.interface.cache and status.interface.cache() or {}
- end
- cache = status.share.refCache or {}
+ local isDeep = status.deep and status.depth == 1
+ local cache = status.share.refCache or {}
+ local deepCache = status.interface.cache and status.interface.cache() or {}
status.share.refCache = cache
if m.isGlobal(obj) then
obj = m.getKeyName(obj)
@@ -2754,22 +2785,42 @@ function m.getRefCache(status, obj, mode)
if not cache[mode] then
cache[mode] = {}
end
- if globalCache and not globalCache[mode] then
- globalCache[mode] = {}
+ if not deepCache[mode] then
+ deepCache[mode] = {}
+ end
+ local sourceCache
+ if isDeep then
+ sourceCache = deepCache[mode][obj]
+ else
+ sourceCache = cache[mode][obj]
end
- local sourceCache = globalCache and globalCache[mode][obj] or cache[mode][obj]
if sourceCache then
return sourceCache
end
sourceCache = {}
cache[mode][obj] = sourceCache
- if globalCache then
- globalCache[mode][obj] = sourceCache
+ if isDeep then
+ deepCache[mode][obj] = sourceCache
end
return nil, function (results)
for i = 1, #results do
sourceCache[i] = results[i]
end
+ if not isDeep then
+ return
+ end
+ if mode == 'ref'
+ or mode == 'def' then
+ for i = 1, #results do
+ local res = results[i]
+ if not deepCache[mode][res] then
+ cache[mode][res] = sourceCache
+ if isDeep then
+ deepCache[mode][res] = sourceCache
+ end
+ end
+ end
+ end
end
end
@@ -3230,6 +3281,13 @@ function m.inferCheckDoc(status, source)
end
return true
end
+ if source.type == 'doc.alias.name' then
+ local results = m.getDocTypeNames(status, m.getDocState(source).extends)
+ for _, res in ipairs(results) do
+ status.results[#status.results+1] = res
+ end
+ return true
+ end
end
function m.getVarargDocType(status, source)
@@ -3766,10 +3824,18 @@ function m.inferByDef(status, obj)
for _, src in ipairs(newStatus.results) do
local inferStatus = m.status(newStatus)
m.searchInfer(inferStatus, src)
- for _, infer in ipairs(inferStatus.results) do
- if not mark[infer.source] then
- mark[infer.source] = true
- status.results[#status.results+1] = infer
+ if #inferStatus.results == 0 then
+ status.results[#status.results+1] = {
+ type = 'any',
+ source = src,
+ level = 0,
+ }
+ else
+ for _, infer in ipairs(inferStatus.results) do
+ if not mark[infer.source] then
+ mark[infer.source] = true
+ status.results[#status.results+1] = infer
+ end
end
end
end
@@ -3797,7 +3863,7 @@ local function inferBySetOfLocal(status, source)
end
end
-function m.inferBySet(status, source)
+function m.inferByLocalRef(status, source)
if #status.results ~= 0 then
return
end
@@ -4183,18 +4249,16 @@ function m.searchInfer(status, obj)
return
end
+ m.inferByLocalRef(status, obj)
if status.deep then
tracy.ZoneBeginN('inferByDef')
m.inferByDef(status, obj)
tracy.ZoneEnd()
end
- m.inferBySet(status, obj)
m.inferByCall(status, obj)
m.inferByGetTable(status, obj)
m.inferByUnary(status, obj)
m.inferByBinary(status, obj)
- m.inferByCallReturn(status, obj)
- m.inferByPCallReturn(status, obj)
m.cleanInfers(status.results, obj)
if makeCache then
makeCache(status.results)
diff --git a/script/parser/luadoc.lua b/script/parser/luadoc.lua
index 9ea674f4..47248ba4 100644
--- a/script/parser/luadoc.lua
+++ b/script/parser/luadoc.lua
@@ -257,6 +257,7 @@ local function parseTypeUnitArray(node)
finish = getFinish(),
node = node,
}
+ node.parent = result
return result
end
@@ -920,6 +921,7 @@ local function buildLuaDoc(comment)
type = 'doc.comment',
start = comment.start,
finish = comment.finish,
+ range = comment.finish,
comment = comment,
}
end
@@ -929,6 +931,7 @@ local function buildLuaDoc(comment)
parseTokens(doc, comment.start + startPos - 1)
local result = convertTokens()
if result then
+ result.range = comment.finish
local cstart = text:find('%S', result.finish - comment.start + 2)
if cstart and cstart < comment.finish then
result.comment = {
@@ -940,7 +943,17 @@ local function buildLuaDoc(comment)
end
end
- return result
+ if result then
+ return result
+ end
+
+ return {
+ type = 'doc.comment',
+ start = comment.start,
+ finish = comment.finish,
+ range = comment.finish,
+ comment = comment,
+ }
end
---当前行在注释doc前是否有代码
diff --git a/script/provider/capability.lua b/script/provider/capability.lua
index e50a40f0..aa1cdb8b 100644
--- a/script/provider/capability.lua
+++ b/script/provider/capability.lua
@@ -5,7 +5,7 @@ local client = require 'provider.client'
local m = {}
local function allWords()
- local str = [[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.:('"[,#*@|= ]]
+ local str = [[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.:('"[,#*@|=- ]]
local list = {}
for c in str:gmatch '.' do
list[#list+1] = c
@@ -32,7 +32,15 @@ function m.getIniter()
documentSymbolProvider = true,
workspaceSymbolProvider = true,
documentHighlightProvider = true,
- codeActionProvider = true,
+ codeActionProvider = {
+ codeActionKinds = {
+ '',
+ 'quickfix',
+ 'refactor.rewrite',
+ 'refactor.extract',
+ },
+ resolveProvider = false,
+ },
signatureHelpProvider = {
triggerCharacters = { '(', ',' },
},
diff --git a/script/provider/completion.lua b/script/provider/completion.lua
index 7a18f2f8..16f2029e 100644
--- a/script/provider/completion.lua
+++ b/script/provider/completion.lua
@@ -3,7 +3,7 @@ local proto = require 'proto'
local isEnable = false
local function allWords()
- local str = [[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.:('"[,#*@|= ]]
+ local str = [[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.:('"[,#*@|=- ]]
local list = {}
for c in str:gmatch '.' do
list[#list+1] = c
diff --git a/script/provider/provider.lua b/script/provider/provider.lua
index 32778399..2d092002 100644
--- a/script/provider/provider.lua
+++ b/script/provider/provider.lua
@@ -35,6 +35,10 @@ local function updateConfig()
}
},
})
+ if not configs or not configs[1] then
+ log.warn('No config?', util.dump(configs))
+ return
+ end
local updated = configs[1]
local other = {
@@ -42,11 +46,6 @@ local function updateConfig()
exclude = configs[3],
}
- if not updated then
- log.warn('No config?', util.dump(configs))
- return
- end
-
local oldConfig = util.deepCopy(config.config)
local oldOther = util.deepCopy(config.other)
config.setConfig(updated, other)
@@ -55,6 +54,7 @@ local function updateConfig()
if not util.equal(oldConfig.runtime, newConfig.runtime) then
library.init()
workspace.reload()
+ semantic.refresh()
end
if not util.equal(oldConfig.diagnostics, newConfig.diagnostics) then
diagnostics.diagnosticsAll()
@@ -67,6 +67,7 @@ local function updateConfig()
or not util.equal(oldOther.exclude, newOther.exclude)
then
workspace.reload()
+ semantic.refresh()
end
if not util.equal(oldConfig.intelliSense, newConfig.intelliSense) then
files.flushCache()
@@ -379,6 +380,7 @@ proto.on('textDocument/completion', function (params)
kind = res.kind,
deprecated = res.deprecated,
sortText = ('%04d'):format(i),
+ filterText = res.filterText,
insertText = res.insertText,
insertTextFormat = 2,
commitCharacters = res.commitCharacters,
diff --git a/script/provider/semantic-tokens.lua b/script/provider/semantic-tokens.lua
index 65235509..e4b2fc6f 100644
--- a/script/provider/semantic-tokens.lua
+++ b/script/provider/semantic-tokens.lua
@@ -1,6 +1,7 @@
local proto = require 'proto'
local define = require 'proto.define'
local client = require 'provider.client'
+local json = require "json"
local isEnable = false
@@ -58,7 +59,13 @@ local function disable()
})
end
+local function refresh()
+ log.debug('Refresh semantic tokens.')
+ proto.notify('workspace/semanticTokens/refresh', json.null)
+end
+
return {
- enable = enable,
+ enable = enable,
disable = disable,
+ refresh = refresh,
}
diff --git a/script/service/telemetry.lua b/script/service/telemetry.lua
index 52ad193b..9fbbfe9e 100644
--- a/script/service/telemetry.lua
+++ b/script/service/telemetry.lua
@@ -60,7 +60,7 @@ local function pushErrorLog(link)
end
timer.wait(5, function ()
- timer.loop(60, function ()
+ timer.loop(300, function ()
if not config.config.telemetry.enable then
return
end
@@ -68,7 +68,7 @@ timer.wait(5, function ()
if not suc then
suc, link = pcall(net.connect, 'tcp', '119.45.194.183', 11577)
end
- if not suc then
+ if not suc or not link then
return
end
function link:on_connect()
diff --git a/script/vm/guideInterface.lua b/script/vm/guideInterface.lua
index 7fd515eb..b464ab98 100644
--- a/script/vm/guideInterface.lua
+++ b/script/vm/guideInterface.lua
@@ -105,3 +105,7 @@ end
function vm.interface.getSearchDepth()
return config.config.intelliSense.searchDepth
end
+
+function vm.interface.pulse()
+ await.delay()
+end
diff --git a/script/workspace/workspace.lua b/script/workspace/workspace.lua
index c493823d..57bdc00f 100644
--- a/script/workspace/workspace.lua
+++ b/script/workspace/workspace.lua
@@ -29,7 +29,7 @@ function m.init(uri)
end
m.uri = uri
m.path = m.normalize(furi.decode(uri))
- local logPath = ROOT / 'log' / (uri:gsub('[/:]+', '_') .. '.log')
+ local logPath = fs.path(LOGPATH) / (uri:gsub('[/:]+', '_') .. '.log')
log.info('Log path: ', logPath)
log.init(ROOT, logPath)
end
@@ -66,7 +66,7 @@ function m.getNativeMatcher()
if not m.path then
return nil
end
- if m.nativeVersion == config.version then
+ if m.nativeMatcher then
return m.nativeMatcher
end
@@ -128,7 +128,7 @@ end
--- 创建代码库筛选器
function m.getLibraryMatchers()
- if m.libraryVersion == config.version then
+ if m.libraryMatchers then
return m.libraryMatchers
end
@@ -172,31 +172,48 @@ end
local function loadFileFactory(root, progress, isLibrary)
return function (path)
local uri = furi.encode(path)
- if not files.isLua(uri) then
- return
- end
- if not isLibrary and progress.preload >= config.config.workspace.maxPreload then
- if not m.hasHitMaxPreload then
- m.hasHitMaxPreload = true
- proto.notify('window/showMessage', {
- type = 3,
- message = lang.script('MWS_MAX_PRELOAD', config.config.workspace.maxPreload),
- })
+ if files.isLua(uri) then
+ if not isLibrary and progress.preload >= config.config.workspace.maxPreload then
+ if not m.hasHitMaxPreload then
+ m.hasHitMaxPreload = true
+ proto.notify('window/showMessage', {
+ type = 3,
+ message = lang.script('MWS_MAX_PRELOAD', config.config.workspace.maxPreload),
+ })
+ end
+ return
+ end
+ if not isLibrary then
+ progress.preload = progress.preload + 1
end
- return
+ progress.max = progress.max + 1
+ pub.task('loadFile', uri, function (text)
+ progress.read = progress.read + 1
+ if text then
+ log.info(('Preload file at: %s , size = %.3f KB'):format(uri, #text / 1000.0))
+ if isLibrary then
+ log.info('++++As library of:', root)
+ files.setLibraryPath(uri, root)
+ end
+ files.setText(uri, text)
+ else
+ files.remove(uri)
+ end
+ end)
end
- if not isLibrary then
- progress.preload = progress.preload + 1
+ if files.isDll(uri) then
+ progress.max = progress.max + 1
+ pub.task('loadFile', uri, function (content)
+ progress.read = progress.read + 1
+ if content then
+ log.info(('Preload file at: %s , size = %.3f KB'):format(uri, #content / 1000.0))
+ if isLibrary then
+ log.info('++++As library of:', root)
+ end
+ files.saveDll(uri, content)
+ end
+ end)
end
- progress.max = progress.max + 1
- pub.task('loadFile', uri, function (text)
- progress.read = progress.read + 1
- --log.info(('Preload file at: %s , size = %.3f KB'):format(uri, #text / 1000.0))
- if isLibrary then
- files.setLibraryPath(uri, root)
- end
- files.setText(uri, text)
- end)
end
end
@@ -239,6 +256,8 @@ end
function m.awaitPreload()
await.close 'preload'
await.setID 'preload'
+ m.libraryMatchers = nil
+ m.nativeMatcher = nil
local progress = {
max = 0,
read = 0,
@@ -249,10 +268,12 @@ function m.awaitPreload()
local native = m.getNativeMatcher()
local librarys = m.getLibraryMatchers()
if native then
+ log.info('Scan files at:', m.path)
native:scan(m.path, nativeLoader)
end
for _, library in ipairs(librarys) do
local libraryLoader = loadFileFactory(library.path, progress, true)
+ log.info('Scan library at:', library.path)
library.matcher:scan(library.path, libraryLoader)
end
@@ -307,6 +328,15 @@ function m.findUrisByRequirePath(path)
local results = {}
local mark = {}
local searchers = {}
+ for uri in files.eachDll() do
+ local opens = files.getDllOpens(uri) or {}
+ for _, open in ipairs(opens) do
+ if open == path then
+ results[#results+1] = uri
+ end
+ end
+ end
+
local input = path:gsub('%.', '/')
:gsub('%%', '%%%%')
for _, luapath in ipairs(config.config.runtime.path) do
diff --git a/test.lua b/test.lua
index cc69416d..6116c16a 100644
--- a/test.lua
+++ b/test.lua
@@ -7,8 +7,10 @@ package.path = package.path
.. ';' .. rootPath .. '/test/?/init.lua'
local fs = require 'bee.filesystem'
ROOT = fs.path(rootPath)
-LANG = 'zh-CN'
TEST = true
+DEVELOP = true
+LOGPATH = LOGPATH or (ROOT .. '/log')
+METAPATH = METAPATH or (ROOT .. '/meta')
collectgarbage 'generational'
diff --git a/test/completion/init.lua b/test/completion/init.lua
index 69ca83c3..eb696eb8 100644
--- a/test/completion/init.lua
+++ b/test/completion/init.lua
@@ -72,6 +72,7 @@ end
config.config.completion.callSnippet = 'Both'
config.config.completion.keywordSnippet = 'Both'
+config.config.completion.workspaceWord = false
TEST [[
local zabcde
@@ -371,7 +372,7 @@ results$
(nil)
TEST [[
-results$
+result$
local results
]]
(EXISTS)
@@ -1220,10 +1221,6 @@ z$
newText = '_ENV["z.b.c"]',
},
},
- {
- label = 'z',
- kind = define.CompletionItemKind.Text,
- }
}
TEST [[
@@ -1970,4 +1967,26 @@ function (${1:x}, ${2:y})\
end",
},
}
+
+TEST [[
+---$
+local function f(a, b, c)
+ return a + 1, b .. '', c[1]
+end
+]]
+{
+ {
+ label = '@param;@return',
+ kind = define.CompletionItemKind.Snippet,
+ insertText = "\z
+${1:comment}\
+---@param a ${2:number}\
+---@param b ${3:string}\
+---@param c ${4:table}\
+---@return ${5:number}\
+---@return ${6:string}\
+---@return ${7:any}",
+ },
+}
+
Cared['insertText'] = nil
diff --git a/test/hover/init.lua b/test/hover/init.lua
index d3d61aed..35222f32 100644
--- a/test/hover/init.lua
+++ b/test/hover/init.lua
@@ -878,7 +878,7 @@ end
]]
[[
function a(b: table)
- -> any
+ -> table
]]
TEST [[
@@ -1264,7 +1264,7 @@ end
local <?x?> = f()
]]
[[
-local x: integer
+local x: any
]]
TEST [[