nixos/lua-lsp/script/workspace/loading.lua

226 lines
6.3 KiB
Lua
Raw Normal View History

local progress = require 'progress'
local lang = require 'language'
local await = require 'await'
local files = require 'files'
local config = require 'config.config'
local client = require 'client'
local util = require 'utility'
local furi = require 'file-uri'
local pub = require 'pub'
---@class workspace.loading
---@field scp scope
---@field _bar progress
---@field _stash function[]
---@field _refs uri[]
---@field _cache table<uri, boolean>
---@field _sets function[]
---@field _removed boolean
local mt = {}
mt.__index = mt
mt._loadLock = false
mt.read = 0
mt.max = 0
mt.preload = 0
function mt:__close()
self:remove()
end
function mt:update()
self._bar:setMessage(('%d/%d'):format(self.read, self.max))
self._bar:setPercentage(self.read / self.max * 100.0)
end
---@param uri uri
function mt:checkMaxPreload(uri)
local max = config.get(uri, 'Lua.workspace.maxPreload')
if self.preload <= max then
return true
end
if self.scp:get 'hasHintedMaxPreload' then
return false
end
self.scp:set('hasHintedMaxPreload', true)
client.requestMessage('Info'
, lang.script('MWS_MAX_PRELOAD', max)
, {
lang.script('WINDOW_INCREASE_UPPER_LIMIT'),
}
, function (_, index)
if index == 1 then
client.setConfig {
{
key = 'Lua.workspace.maxPreload',
uri = self.scp.uri,
action = 'set',
value = max + math.max(1000, max),
}
}
end
end
)
return false
end
---@param uri uri
---@param libraryUri? uri
---@async
function mt:loadFile(uri, libraryUri)
if files.isLua(uri) then
if not libraryUri then
self.preload = self.preload + 1
if not self:checkMaxPreload(uri) then
return
end
end
self.max = self.max + 1
self:update()
---@async
self._stash[#self._stash+1] = function ()
if files.getFile(uri) then
self.read = self.read + 1
self:update()
if not self._cache[uri] then
files.addRef(uri)
end
self._cache[uri] = true
log.debug(('Skip loaded file: %s'):format(uri))
else
local content = pub.awaitTask('loadFile', furi.decode(uri))
self.read = self.read + 1
self:update()
if not content then
return
end
log.debug(('Preload file at: %s , size = %.3f KB'):format(uri, #content / 1024.0))
--await.wait(function (waker)
-- self._sets[#self._sets+1] = waker
--end)
files.setText(uri, content, false)
if COMPILECORES then
files.compileStateAsync(uri, function (state) end)
else
files.compileState(uri)
end
if not self._cache[uri] then
files.addRef(uri)
end
self._cache[uri] = true
end
if libraryUri then
log.debug('++++As library of:', libraryUri)
end
end
elseif files.isDll(uri) then
self.max = self.max + 1
self:update()
---@async
self._stash[#self._stash+1] = function ()
if files.getFile(uri) then
self.read = self.read + 1
self:update()
if not self._cache[uri] then
files.addRef(uri)
end
self._cache[uri] = true
log.debug(('Skip loaded file: %s'):format(uri))
else
local content = pub.awaitTask('loadFile', furi.decode(uri))
self.read = self.read + 1
self:update()
if not content then
return
end
log.debug(('Preload dll at: %s , size = %.3f KB'):format(uri, #content / 1024.0))
--await.wait(function (waker)
-- self._sets[#self._sets+1] = waker
--end)
files.saveDll(uri, content)
if not self._cache[uri] then
files.addRef(uri)
end
self._cache[uri] = true
end
if libraryUri then
log.debug('++++As library of:', libraryUri)
end
end
end
await.delay()
end
---@async
function mt:loadAll(fileName)
local startClock = os.clock()
log.info('Load files from disk:', fileName)
while self.read < self.max do
self:update()
local loader = table.remove(self._stash)
if loader then
await.call(loader)
await.delay()
else
await.sleep(0.1)
end
end
local loadedClock = os.clock()
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
await.delay()
set()
self.read = i
self:update()
end
log.info(('Compile files takes [%.3f] sec: %s'):format(os.clock() - loadedClock, fileName))
log.info('Loaded finish:', fileName)
end
function mt:remove()
if self._removed then
return
end
self._removed = true
self._bar:remove()
end
function mt:isRemoved()
return self._removed == true
end
---@class workspace.loading.manager
local m = {}
---@type table<workspace.loading, boolean>
m._loadings = setmetatable({}, { __mode = 'k' })
---@return workspace.loading
function m.create(scp)
local loading = setmetatable({
scp = scp,
_bar = progress.create(scp.uri, lang.script('WORKSPACE_LOADING', scp.uri), 0.5),
_stash = {},
_cache = {},
_sets = {},
}, mt)
m._loadings[loading] = true
return loading
end
function m.count()
local num = 0
for ld in pairs(m._loadings) do
if ld:isRemoved() then
m._loadings[ld] = nil
else
num = num + 1
end
end
return num
end
return m