diff options
Diffstat (limited to 'server')
-rw-r--r-- | server/src/files/file.lua | 71 | ||||
-rw-r--r-- | server/src/files/files.lua | 100 | ||||
-rw-r--r-- | server/src/files/init.lua | 48 | ||||
-rw-r--r-- | server/src/meta.lua | 2 | ||||
-rw-r--r-- | server/src/service.lua | 288 |
5 files changed, 298 insertions, 211 deletions
diff --git a/server/src/files/file.lua b/server/src/files/file.lua index e8cd783b..deaea8ba 100644 --- a/server/src/files/file.lua +++ b/server/src/files/file.lua @@ -1,33 +1,90 @@ +---@class file local mt = {} mt.__index = mt mt.type = 'file' mt._uri = '' mt._text = '' -mt._open = false +mt._version = -1 +---@param buf string function mt:setText(buf) self._text = buf end +---@return string function mt:getText() return self._text end -function mt:open() - self._open = true +---@param version integer +function mt:setVersion(version) + self._version = version end -function mt:close() - self._open = false +---@return integer +function mt:getVersion() + return self._version end -function mt:isOpen() - return self._open +function mt:remove() + if self._removed then + return + end + self._removed = true + self._text = nil + self._version = nil + if self._vm then + self._vm:remove() + end end +---@param vm VM +function mt:saveVM(vm) + self._vm = vm +end + +---@return VM +function mt:getVM() + return self._vm +end + +function mt:removeVM() + if not self._vm then + return + end + self._vm:remove() + self._vm = nil +end + +---@return file +function mt:getParent() + return self._parent +end + +---@param uri uri +function mt:removeChild(uri) + self._child[uri] = nil +end + +---@param uri uri +function mt:removeParent(uri) + self._parent[uri] = nil +end + +function mt:eachChild() + return pairs(self._child) +end + +function mt:eachParent() + return pairs(self._parent) +end + +---@param uri string return function (uri) local self = setmetatable({ _uri = uri, + _parent = {}, + _child = {}, }, mt) return self end diff --git a/server/src/files/files.lua b/server/src/files/files.lua new file mode 100644 index 00000000..4f5b064e --- /dev/null +++ b/server/src/files/files.lua @@ -0,0 +1,100 @@ +local file = require 'files.file' + +---@class files +local mt = {} +mt.__index = mt +mt.type = 'files' +mt._fileCount = 0 +---@type table<uri, file> +mt._files = nil + +---@param uri uri +---@param text string +function mt:save(uri, text, version) + local f = self._files[uri] + if not f then + f = file(uri) + self._files[uri] = f + self._fileCount = self._fileCount + 1 + end + f:setText(text) + f:setVersion(version) +end + +---@param uri uri +function mt:remove(uri) + local f = self._files[uri] + if not f then + return + end + + f:remove() + self._files[uri] = nil + self._fileCount = self._fileCount - 1 +end + +---@param uri uri +function mt:open(uri) + self._open[uri] = true +end + +---@param uri uri +function mt:close(uri) + self._open[uri] = nil +end + +---@param uri uri +---@return boolean +function mt:isOpen(uri) + return self._open[uri] == true +end + +---@param uri uri +function mt:isDead(uri) + local f = self._files[uri] + if not f then + return true + end + if f:isRemoved() then + return true + end + return f:getVersion() == -1 +end + +---@param uri uri +---@return file +function mt:get(uri) + return self._files[uri] +end + +---@param uri uri +---@param vm VM +function mt:saveVM(uri, vm) + local f = self._files[uri] + if not f then + return + end + f:saveVM(vm) +end + +function mt:clear() + for _, f in pairs(self._files) do + f:remove() + end +end + +function mt:eachFile() + return pairs(self._files) +end + +function mt:eachOpened() + return pairs(self._open) +end + +return function () + local self = setmetatable({ + _files = {}, + _open = {}, + }, mt) + return self +end diff --git a/server/src/files/init.lua b/server/src/files/init.lua index 79e5c115..e090874d 100644 --- a/server/src/files/init.lua +++ b/server/src/files/init.lua @@ -1,47 +1 @@ -local file = require 'files.file' - -local mt = {} -mt.__index = mt -mt.type = 'files' - -function mt:save(uri) - if not self._files[uri] then - self._files[uri] = file(uri) - end - self._files[uri]:setText(uri) -end - -function mt:remove(uri) - local obj = self._files[uri] - - self._files[uri] = nil -end - -function mt:open(uri) - if not self._files[uri] then - self._files[uri] = file(uri) - end - self._files[uri]:open() -end - -function mt:close(uri) - if not self._files[uri] then - return - end - self._files[uri]:close() -end - -function mt:isOpen(uri) - local obj = self._files[uri] - if not obj then - return false - end - return obj:isOpen() -end - -return function () - local self = setmetatable({ - _files = {}, - }, mt) - return self -end +return require 'files.files' diff --git a/server/src/meta.lua b/server/src/meta.lua new file mode 100644 index 00000000..c6fb3a38 --- /dev/null +++ b/server/src/meta.lua @@ -0,0 +1,2 @@ +---@class uri string +---@class path diff --git a/server/src/service.lua b/server/src/service.lua index 945cd939..ef601393 100644 --- a/server/src/service.lua +++ b/server/src/service.lua @@ -17,6 +17,7 @@ local listMgr = require 'vm.list' local emmyMgr = require 'emmy.manager' local config = require 'config' local task = require 'task' +local files = require 'files' local ErrorCodes = { -- Defined by JSON RPC @@ -38,6 +39,8 @@ local CachedVM = setmetatable({}, {__mode = 'kv'}) local mt = {} mt.__index = mt +---@type files +mt._files = nil function mt:_callMethod(name, params) local optional @@ -116,16 +119,20 @@ function mt:clearDiagnostics(uri) self._needDiagnostics[uri] = nil end +---@param uri uri +---@param compiled table +---@param mode string +---@return boolean function mt:needCompile(uri, compiled, mode) self._needDiagnostics[uri] = true if self._needCompile[uri] then - return + return false end if not compiled then compiled = {} end if compiled[uri] then - return + return false end self._needCompile[uri] = compiled if mode == 'child' then @@ -133,6 +140,7 @@ function mt:needCompile(uri, compiled, mode) else table.insert(self._needCompile, 1, uri) end + return true end function mt:isNeedCompile(uri) @@ -147,83 +155,78 @@ function mt:isWaitingCompile() end end +---@param uri uri +---@param version integer +---@param text string function mt:saveText(uri, version, text) self._lastLoadedVM = uri - local obj = self._file[uri] - if obj then - obj.version = version - obj.oldText = obj.text - obj.text = text - self:needCompile(uri) - else - self._fileCount = self._fileCount + 1 - self._file[uri] = { - version = version, - text = text, - uri = uri, - } - self:needCompile(uri) - end + self._files:save(uri, text, version) + self:needCompile(uri) end +---@param uri uri function mt:isDeadText(uri) - local obj = self._file[uri] - if not obj then + return self._files:isDead(uri) +end + +---@param uri uri +---@return boolean +function mt:isLua(uri) + if not self.workspace then + return true + end + local path = self.workspace:relativePathByUri(uri) + if self.workspace:isLuaFile(path) then + return true + end + return false +end + +function mt:isIgnored(uri) + if not self.workspace then return true end - if obj.version == -1 then + local path = self.workspace:relativePathByUri(uri) + if self.workspace.gitignore(path:string()) then return true end return false end +---@param uri uri +---@param version integer +---@param text string function mt:open(uri, version, text) - if self.workspace then - local path = self.workspace:relativePathByUri(uri) - if not self.workspace:isLuaFile(path) then - return - end - if self.workspace.gitignore(path:string()) then - log.debug('Open ignored file:', path:string()) - end + if not self:isLua(uri) then + return end self:saveText(uri, version, text) - local obj = self._file[uri] - if obj then - obj._openByClient = true - end + self._files:open(uri) end +---@param uri uri function mt:close(uri) - local obj = self._file[uri] - if obj then - obj._openByClient = false - end - if self.workspace then - local path = self.workspace:relativePathByUri(uri) - if not self.workspace:isLuaFile(path) then - self:removeText(uri) - return - end - if self.workspace.gitignore(path:string()) then - log.debug('Close ignored file:', path:string()) - self:removeText(uri) - end + self._files:close(uri) + if not self:isLua() or self:isIgnored(uri) then + self:removeText(uri) end end +---@param uri uri +---@return boolean function mt:isOpen(uri) - local obj = self._file[uri] - if obj and obj._openByClient then - return true - else - return false - end + return self._files:isOpen(uri) end +---@param uri uri +---@param path path +---@param buf string +---@param compiled table function mt:readText(uri, path, buf, compiled) - local obj = self._file[uri] - if obj then + if self._files:get(uri) then + return + end + if not self:isLua(uri) or self:isIgnored(uri) then return end local text = buf or io.load(path) @@ -231,15 +234,6 @@ function mt:readText(uri, path, buf, compiled) log.debug('No file: ', path) return end - if self.workspace then - local path = self.workspace:relativePathByUri(uri) - if not self.workspace:isLuaFile(path) then - return - end - if self.workspace.gitignore(path:string()) then - return - end - end local size = #text / 1000.0 if size > config.config.workspace.preloadFileSize then log.info(('Skip large file, size: %.3f KB: %s'):format(size, uri)) @@ -255,30 +249,14 @@ function mt:readText(uri, path, buf, compiled) end return end - self._fileCount = self._fileCount + 1 - self._file[uri] = { - version = 0, - text = text, - uri = uri, - } + self._files:save(uri, text, 0) self:needCompile(uri, compiled) end +---@param uri uri function mt:removeText(uri) - local obj = self._file[uri] - if not obj then - return - end - self._fileCount = self._fileCount - 1 - self:saveText(uri, -1, '') + self._files:remove(uri) self:compileVM(uri) - -- TODO 以后重构一下,把缓存的text作为一个单独的类管理 - local vm = self._file[uri].vm - if vm then - vm:remove() - end - self._file[uri].removed = true - self._file[uri] = nil end function mt:getCachedFileCount() @@ -296,59 +274,57 @@ function mt:reCompile() self.emmy:remove() end + local reload = {} + for uri in self._files:eachFile() do + reload[uri] = true + end + for uri in self._files:eachOpened() do + reload[uri] = true + end + + self._files:clear() + for _, obj in pairs(listMgr.list) do if obj.type == 'source' or obj.type == 'function' then obj:kill() end end - for _, obj in pairs(self._file) do - if obj.vm then - obj.vm:remove() - obj.vm = nil - end - end self.global = core.global(self) self.chain = chainMgr() self.emmy = emmyMgr() self.globalValue = nil - self._compileTask = nil - + self._compileTask:remove() self._needCompile = {} - - ac.wait(0.5, function () - local compiled = {} - local n = 0 - for uri in pairs(self._file) do - self:needCompile(uri, compiled) + local compiled = {} + local n = 0 + for uri in pairs(reload) do + local suc = self:needCompile(uri, compiled) + if suc then n = n + 1 end - log.debug('reCompile:', n) - self:_testMemory() - end) + end + log.debug('reCompile:', n) + self:_testMemory() end function mt:reDiagnostic() - for uri in pairs(self._file) do + for uri in self._files:eachFile() do self:clearDiagnostics(uri) + self._needDiagnostics[uri] = true end - ac.wait(0.5, function () - for uri in pairs(self._file) do - self._needDiagnostics[uri] = true - end - end) end function mt:clearAllFiles() - for uri in pairs(self._file) do - self:removeText(uri) + for uri in self._files:eachFile() do self:clearDiagnostics(uri) end + self._files:clear() end function mt:loadVM(uri) - local obj = self._file[uri] - if not obj then + local file = self._files:get(uri) + if not file then return nil end if uri ~= self._lastLoadedVM then @@ -362,10 +338,10 @@ function mt:loadVM(uri) else self:compileVM(uri) end - if obj.vm then + if file:getVM() then self._lastLoadedVM = uri end - return obj.vm, obj.lines, obj.text + return file end function mt:_markCompiled(uri, compiled) @@ -392,10 +368,11 @@ function mt:_markCompiled(uri, compiled) return compiled end -function mt:compileAst(obj) - local ast, err = parser:ast(obj.text, 'lua', config.config.runtime.version) +---@param file file +function mt:compileAst(file) + local ast, err = parser:ast(file.text, 'lua', config.config.runtime.version) if ast then - obj.astErr = err + file.astErr = err else if type(err) == 'string' then local message = lang.script('PARSER_CRASH', err) @@ -412,30 +389,28 @@ function mt:compileAst(obj) return ast end -function mt:_clearChainNode(obj, uri) - if obj.parent then - for pUri in pairs(obj.parent) do - local parent = self._file[pUri] - if parent and parent.child then - parent.child[uri] = nil - end +---@param file file +---@param uri uri +function mt:_clearChainNode(file, uri) + for pUri in file:eachParent() do + local parent = self._files:get(pUri) + if parent then + parent:removeChild(uri) end end end -function mt:_compileChain(obj, compiled) +---@param file file +---@param compiled table +function mt:_compileChain(file, compiled) if not compiled then compiled = {} end - if obj.child then - for uri in pairs(obj.child) do - self:needCompile(uri, compiled, 'child') - end + for uri in file:eachChild() do + self:needCompile(uri, compiled, 'child') end - if obj.parent then - for uri in pairs(obj.parent) do - self:needCompile(uri, compiled, 'parent') - end + for uri in file:eachParent() do + self:needCompile(uri, compiled, 'parent') end end @@ -454,9 +429,10 @@ function mt:_hasSetGlobal(uri) return self.global:hasSetGlobal(uri) end +---@param uri uri function mt:compileVM(uri) - local obj = self._file[uri] - if not obj then + local file = self._files:get(uri) + if not file then self:_markCompiled(uri) return nil end @@ -464,21 +440,18 @@ function mt:compileVM(uri) if not compiled then return nil end - if obj.vm then - obj.vm:remove() - obj.vm = nil - end + file:removeVM() local clock = os.clock() - local ast = self:compileAst(obj) - local version = obj.version - obj.astCost = os.clock() - clock - if obj.astCost > 0.1 then - log.warn(('Compile Ast[%s] takes [%.3f] sec, size [%.3f]kb'):format(uri, obj.astCost, #obj.text / 1000)) + local ast = self:compileAst(file) + local version = file.version + file.astCost = os.clock() - clock + if file.astCost > 0.1 then + log.warn(('Compile Ast[%s] takes [%.3f] sec, size [%.3f]kb'):format(uri, file.astCost, #file.text / 1000)) end - obj.oldText = nil + file.oldText = nil - self:_clearChainNode(obj, uri) + self:_clearChainNode(file, uri) self:_clearGlobal(uri) local clock = os.clock() @@ -486,13 +459,13 @@ function mt:compileVM(uri) if vm then CachedVM[vm] = true end - if self:isDeadText(uri) or obj.removed then + if self:isDeadText(uri) or file.removed then if vm then vm:remove() end return nil end - if version ~= obj.version then + if version ~= file.version then if vm then vm:remove() end @@ -507,30 +480,30 @@ function mt:compileVM(uri) end return nil end - if obj.vm then - obj.vm:remove() + if file.vm then + file.vm:remove() end - obj.vm = vm - obj.vmCost = os.clock() - clock - obj.vmVersion = version + file.vm = vm + file.vmCost = os.clock() - clock + file.vmVersion = version local clock = os.clock() - obj.lines = parser:lines(obj.text, 'utf8') - obj.lineCost = os.clock() - clock + file.lines = parser:lines(file.text, 'utf8') + file.lineCost = os.clock() - clock - if obj.vmCost > 0.2 then - log.debug(('Compile VM[%s] takes: %.3f sec'):format(uri, obj.vmCost)) + if file.vmCost > 0.2 then + log.debug(('Compile VM[%s] takes: %.3f sec'):format(uri, file.vmCost)) end - if not obj.vm then + if not file.vm then error(err) end - self:_compileChain(obj, compiled) + self:_compileChain(file, compiled) if self:_hasSetGlobal(uri) then self:_compileGlobal(compiled) end - return obj + return file end function mt:doDiagnostics(uri) @@ -962,6 +935,7 @@ return function () _needDiagnostics = {}, _clock = -100, _version = 0, + _files = files(), }, mt) session.global = core.global(session) session.chain = chainMgr() |