summaryrefslogtreecommitdiff
path: root/script
diff options
context:
space:
mode:
Diffstat (limited to 'script')
-rw-r--r--script/files.lua32
-rw-r--r--script/lazy-cacher.lua219
-rw-r--r--script/lazytable.lua106
-rw-r--r--script/provider/diagnostic.lua3
-rw-r--r--script/workspace/loading.lua11
-rw-r--r--script/workspace/workspace.lua4
6 files changed, 228 insertions, 147 deletions
diff --git a/script/files.lua b/script/files.lua
index 7a13e06a..c759f038 100644
--- a/script/files.lua
+++ b/script/files.lua
@@ -33,6 +33,7 @@ local sp = require 'bee.subprocess'
---@field id integer
---@class files
+---@field lazyCache? lazy-cacher
local m = {}
m.watchList = {}
@@ -477,6 +478,17 @@ function m.eachDll()
return pairs(map)
end
+function m.getLazyCache()
+ if not m.lazyCache then
+ local cachePath = string.format('%s/cache/%d'
+ , LOGPATH
+ , sp.get_id()
+ )
+ m.lazyCache = cacher(cachePath, log.error)
+ end
+ return m.lazyCache
+end
+
function m.compileState(uri, text)
local ws = require 'workspace'
local client = require 'client'
@@ -534,20 +546,12 @@ function m.compileState(uri, text)
local file = m.fileMap[uri]
if LAZY and not file.trusted then
- local clock = os.clock()
- local myCacheDir = string.format('%s/cache/%d'
- , LOGPATH
- , sp.get_id()
- )
- local cachePath = string.format('%s/%d'
- , myCacheDir
- , file.id
- )
- local cache = cacher(cachePath, log.error)
- if cache then
- state = lazy.build(state, cache.writter, cache.reader):entry()
- end
- local passed = os.clock() - clock
+ state.pushError = nil
+ local cache = m.getLazyCache()
+ local id = ('%d'):format(file.id)
+ clock = os.clock()
+ state = lazy.build(state, cache:writterAndReader(id)):entry()
+ passed = os.clock() - clock
if passed > 0.1 then
log.warn(('Convert lazy-table for [%s] takes [%.3f] sec, size [%.3f] kb.'):format(uri, passed, #text / 1000))
end
diff --git a/script/lazy-cacher.lua b/script/lazy-cacher.lua
index e39cceff..d6b29ba9 100644
--- a/script/lazy-cacher.lua
+++ b/script/lazy-cacher.lua
@@ -1,70 +1,171 @@
-local fs = require 'bee.filesystem'
+local fs = require 'bee.filesystem'
+local linkedTable = require 'linked-table'
----@param path string
----@param errorHandle? fun(string)
----@return table?
-return function (path, errorHandle)
- fs.create_directories(fs.path(path):parent_path())
- local f, err = io.open(path, 'a+b')
- if not f then
- if errorHandle then
- errorHandle(err)
- end
- return nil
+local setmt = setmetatable
+local pairs = pairs
+local iopen = io.open
+local mmax = math.max
+
+_ENV = nil
+
+---@class lazy-cacher
+---@field _opening linked-table
+---@field _openingMap table<string, file*>
+---@field _dir string
+local mt = {}
+mt.__index = mt
+mt.type = 'lazy-cacher'
+
+mt.maxOpendFiles = 50
+mt.maxFileSize = 100 * 1024 * 1024 -- 100MB
+mt.openingFiles = {}
+
+mt.errorHandler = function (err) end
+
+---@param fileID string
+function mt:_closeFile(fileID)
+ self._opening:pop(fileID)
+ self._openingMap[fileID]:close()
+ self._openingMap[fileID] = nil
+end
+
+---@param fileID string
+---@return file*?
+---@return string? errorMessage
+function mt:_getFile(fileID)
+ if self._openingMap[fileID] then
+ self._opening:pop(fileID)
+ self._opening:pushTail(fileID)
+ return self._openingMap[fileID]
end
- local size, err = f:seek('end')
- if not size then
- if errorHandle then
- errorHandle(err)
- end
- return nil
+ local fullPath = self._dir .. '/' .. fileID
+ local file, err = iopen(fullPath, 'a+b')
+ if not file then
+ return nil, err
+ end
+ self._opening:pushTail(fileID)
+ self._openingMap[fileID] = file
+ if self._opening:getSize() > self.maxOpendFiles then
+ local oldest = self._opening:getHead()
+ self:_closeFile(oldest)
end
+ return file
+end
+
+---@param fileID string
+---@return fun(id: integer, code: string): boolean
+---@return fun(id: integer): string?
+function mt:writterAndReader(fileID)
+ local maxFileSize = self.maxFileSize
local map = {}
- return {
- writter = function(id, code)
- local offset, err = f:seek('end')
- if not offset then
- if errorHandle then
- errorHandle(err)
- end
- return false
- end
- if not code then
- map[id] = nil
- return true
- end
- if #code > 1000000 then
- return false
- end
- local suc, err = f:write(code)
+ ---@param file file*
+ local function resize(file)
+ local codes = {}
+ for id, data in pairs(map) do
+ local offset = data // 1000000
+ local len = data % 1000000
+ local suc, err = file:seek('set', offset)
if not suc then
- if errorHandle then
- errorHandle(err)
- end
- return false
+ self.errorHandler(err)
+ return
end
+ local code = file:read(len)
+ codes[id] = code
+ end
+
+ self:_closeFile(fileID)
+ local fullPath = self._dir .. '/' .. fileID
+ local file, err = iopen(fullPath, 'wb')
+ if not file then
+ self.errorHandler(err)
+ return
+ end
+
+ local offset = 0
+ for id, code in pairs(codes) do
+ file:write(code)
map[id] = offset * 1000000 + #code
+ offset = offset + #code
+ end
+ file:close()
+ end
+ ---@param id integer
+ ---@param code string
+ ---@return boolean
+ local function writter(id, code)
+ if not code then
+ map[id] = nil
return true
- end,
- reader = function(id)
- if not map[id] then
- return nil
+ end
+ if #code > 1000000 then
+ return false
+ end
+ local file, err = self:_getFile(fileID)
+ if not file then
+ self.errorHandler(err)
+ return false
+ end
+ local offset, err = file:seek('end')
+ if not offset then
+ self.errorHandler(err)
+ return false
+ end
+ if offset > maxFileSize then
+ resize(file)
+ file, err = self:_getFile(fileID)
+ if not file then
+ self.errorHandler(err)
+ return false
end
- local offset = map[id] // 1000000
- local len = map[id] % 1000000
- local _, err = f:seek('set', offset)
- if err then
- if errorHandle then
- errorHandle(err)
- end
- return nil
+ offset, err = file:seek('end')
+ if not offset then
+ self.errorHandler(err)
+ return false
end
- local code = f:read(len)
- return code
- end,
- dispose = function ()
- f:close()
- fs.remove(fs.path(path))
- end,
- }
+ maxFileSize = mmax(maxFileSize, (offset + #code) * 2)
+ end
+ local suc, err = file:write(code)
+ if not suc then
+ self.errorHandler(err)
+ return false
+ end
+ map[id] = offset * 1000000 + #code
+ return true
+ end
+ ---@param id integer
+ ---@return string?
+ local function reader(id)
+ if not map[id] then
+ return nil
+ end
+ local file, err = self:_getFile(fileID)
+ if not file then
+ self.errorHandler(err)
+ return nil
+ end
+ local offset = map[id] // 1000000
+ local len = map[id] % 1000000
+ local suc, err = file:seek('set', offset)
+ if not suc then
+ self.errorHandler(err)
+ return nil
+ end
+ local code = file:read(len)
+ return code
+ end
+ return writter, reader
+end
+
+---@param dir string
+---@param errorHandle? fun(string)
+---@return lazy-cacher?
+return function (dir, errorHandle)
+ fs.create_directories(fs.path(dir))
+ local self = setmt({
+ _dir = dir,
+ _opening = linkedTable(),
+ _openingMap = {},
+ errorHandler = errorHandle,
+ }, mt)
+ return self
end
diff --git a/script/lazytable.lua b/script/lazytable.lua
index 9ac9c468..d162b4c8 100644
--- a/script/lazytable.lua
+++ b/script/lazytable.lua
@@ -1,3 +1,18 @@
+local type = type
+local pairs = pairs
+local error = error
+local next = next
+local load = load
+local setmt = setmetatable
+local rawset = rawset
+local sdump = string.dump
+local sbyte = string.byte
+local smatch = string.match
+local sformat = string.format
+local tconcat = table.concat
+
+_ENV = nil
+
---@class lazytable.builder
---@field source table
---@field codeMap table<integer, string>
@@ -41,59 +56,21 @@ local RESERVED = {
---@return string
local function formatKey(k)
if type(k) == 'string' then
- if not RESERVED[k] and k:match '^[%a_][%w_]*$' then
+ if not RESERVED[k] and smatch(k, '^[%a_][%w_]*$') then
return k
else
- return ('[%q]'):format(k)
+ return sformat('[%q]', k)
end
end
if type(k) == 'number' then
- if math.type(k) == 'integer' then
- local n10 = ('%d'):format(k)
- local n16 = ('0x%X'):format(k)
- if #n10 <= #n16 then
- return '[' .. n10 .. ']'
- else
- return '[' .. n16 .. ']'
- end
- else
- local n10 = ('%.16f'):format(k):gsub('0+$', '')
- local n16 = ('%q'):format(k)
- if #n10 <= #n16 then
- return '[' .. n10 .. ']'
- else
- return '[' .. n16 .. ']'
- end
- end
+ return sformat('[%q]', k)
end
error('invalid key type: ' .. type(k))
end
---@param v string|number|boolean
local function formatValue(v)
- if type(v) == 'string' then
- return ('%q'):format(v)
- end
- if type(v) == 'number' then
- if math.type(v) == 'integer' then
- local n10 = ('%d'):format(v)
- local n16 = ('0x%X'):format(v)
- if #n10 <= #n16 then
- return n10
- else
- return n16
- end
- else
- local n10 = ('%.16f'):format(v):gsub('0+$', '')
- local n16 = ('%q'):format(v)
- if #n10 <= #n16 then
- return n10
- else
- return n16
- end
- end
- end
- return ('%q'):format(v)
+ return sformat('%q', v)
end
---@param info {[1]: table, [2]: integer, [3]: table?}
@@ -109,14 +86,14 @@ local function dump(info)
else
hasFields = true
end
- codeBuf[#codeBuf+1] = string.format('%s=%s'
+ codeBuf[#codeBuf+1] = sformat('%s=%s'
, formatKey(k)
, formatValue(v)
)
end
codeBuf[#codeBuf+1] = '}'
- codeBuf[#codeBuf+1] = string.format(',%d', formatValue(info[2]))
+ codeBuf[#codeBuf+1] = sformat(',%d', formatValue(info[2]))
if info[3] then
codeBuf[#codeBuf+1] = ',{'
@@ -127,7 +104,7 @@ local function dump(info)
else
hasFields = true
end
- codeBuf[#codeBuf+1] = string.format('%s=%s'
+ codeBuf[#codeBuf+1] = sformat('%s=%s'
, formatKey(k)
, formatValue(v)
)
@@ -137,7 +114,7 @@ local function dump(info)
codeBuf[#codeBuf + 1] = '}'
- return table.concat(codeBuf)
+ return tconcat(codeBuf)
end
---@param obj table|function|userdata|thread
@@ -183,7 +160,7 @@ end
---@param writter fun(id: integer, code: string): boolean
---@param reader fun(id: integer): string?
function mt:bind(writter, reader)
- setmetatable(self.codeMap, {
+ setmt(self.codeMap, {
__newindex = function (t, id, code)
local suc = writter(id, code)
if not suc then
@@ -209,11 +186,6 @@ function mt:entry()
local codeMap = self.codeMap
local refMap = self.refMap
local instMap = self.instMap
- local load = load
- local setmt = setmetatable
- local sdump = string.dump
- local type = type
- local sbyte = string.byte
local tableID = self.tableID
---@type table<table, integer>
local idMap = {}
@@ -230,9 +202,9 @@ function mt:entry()
if not f then
return nil
end
- if sbyte(code, 1, 1) ~= 27 then
- codeMap[id] = sdump(f, true)
- end
+ --if sbyte(code, 1, 1) ~= 27 then
+ -- codeMap[id] = sdump(f, true)
+ --end
local info = f()
map[t] = info
return info
@@ -268,12 +240,10 @@ function mt:entry()
return instMap[ref]
end,
__newindex = function(t, k, v)
- local info = infoMap[t]
- if not info then
- return
- end
- local fields = info[1]
- local objs = info[3]
+ local info = infoMap[t]
+ local fields = info and info[1] or {}
+ local len = info and info[2] or 0
+ local objs = info and info[3]
fields[k] = nil
if objs then
objs[k] = nil
@@ -286,7 +256,7 @@ function mt:entry()
if not objs then
objs = {}
end
- local id = refMap[v]
+ local id = refMap[v] or idMap[v]
if not id then
id = tableID
refMap[v] = id -- 新赋值的对象一定会被引用住
@@ -296,11 +266,12 @@ function mt:entry()
objs[k] = id
end
end
- info = { fields, info[2], objs }
+ info = { fields, len, objs }
local id = idMap[t]
local code = dump(info)
- codeMap[id] = code
infoMap[id] = nil
+ codeMap[id] = nil
+ codeMap[id] = code
end,
__len = function (t)
local info = infoMap[t]
@@ -334,9 +305,9 @@ function mt:entry()
end,
}
- setmetatable(idMap, { __mode = 'k' })
+ setmt(idMap, { __mode = 'k' })
- setmetatable(instMap, {
+ setmt(instMap, {
__mode = 'v',
__index = function (map, id)
local inst = {}
@@ -350,6 +321,7 @@ function mt:entry()
local entry = instMap[entryID] --[[@as table]]
self.source = nil
+ self.dumpMark = nil
return entry
end
@@ -362,7 +334,7 @@ local m = {}
---@param reader? fun(id: integer): string?
---@return lazytable.builder
function m.build(t, writter, reader)
- local builder = setmetatable({
+ local builder = setmt({
source = t,
codeMap = {},
refMap = {},
diff --git a/script/provider/diagnostic.lua b/script/provider/diagnostic.lua
index 46ea600f..22287698 100644
--- a/script/provider/diagnostic.lua
+++ b/script/provider/diagnostic.lua
@@ -511,6 +511,9 @@ function m.diagnosticsScope(uri, force)
m.clearAll()
return
end
+ if not force and config.get(uri, 'Lua.diagnostics.workspaceDelay') < 0 then
+ return
+ end
local scp = scope.getScope(uri)
local id = 'diagnosticsScope:' .. scp:getName()
await.close(id)
diff --git a/script/workspace/loading.lua b/script/workspace/loading.lua
index 468e1908..9344949c 100644
--- a/script/workspace/loading.lua
+++ b/script/workspace/loading.lua
@@ -99,6 +99,7 @@ function mt:loadFile(uri, libraryUri)
-- self._sets[#self._sets+1] = waker
--end)
files.setText(uri, content, false)
+ files.getState(uri)
if not self._cache[uri] then
files.addRef(uri)
end
@@ -147,9 +148,9 @@ function mt:loadFile(uri, libraryUri)
end
---@async
-function mt:loadAll()
+function mt:loadAll(fileName)
local startClock = os.clock()
- log.info('Load files from disk:', self.scp:getName())
+ log.info('Load files from disk:', fileName)
while self.read < self.max do
self:update()
local loader = table.remove(self._stash)
@@ -161,7 +162,7 @@ function mt:loadAll()
end
end
local loadedClock = os.clock()
- log.info(('Loaded files takes [%.3f] sec: %s'):format(loadedClock - startClock, self.scp:getName()))
+ log.info(('Loaded files takes [%.3f] sec: %s'):format(loadedClock - startClock, fileName))
self._bar:remove()
self._bar = progress.create(self.scp.uri, lang.script('WORKSPACE_LOADING', self.scp.uri), 0)
for i, set in ipairs(self._sets) do
@@ -170,8 +171,8 @@ function mt:loadAll()
self.read = i
self:update()
end
- log.info(('Compile files takes [%.3f] sec: %s'):format(os.clock() - loadedClock, self.scp:getName()))
- log.info('Loaded finish:', self.scp:getName())
+ log.info(('Compile files takes [%.3f] sec: %s'):format(os.clock() - loadedClock, fileName))
+ log.info('Loaded finish:', fileName)
end
function mt:remove()
diff --git a/script/workspace/workspace.lua b/script/workspace/workspace.lua
index 9d2ad637..1b94f389 100644
--- a/script/workspace/workspace.lua
+++ b/script/workspace/workspace.lua
@@ -269,7 +269,7 @@ function m.awaitLoadFile(uri)
scp:get('cachedUris')[uri] = true
ld:loadFile(uri)
end)
- ld:loadAll()
+ ld:loadAll(uri)
end
function m.removeFile(uri)
@@ -346,7 +346,7 @@ function m.awaitPreload(scp)
await.sleep(0.1)
log.info(('Found %d files at:'):format(ld.max), scp:getName())
- ld:loadAll()
+ ld:loadAll(scp:getName())
log.info('Preload finish at:', scp:getName())
end