diff options
-rw-r--r-- | server/src/lsp.lua | 77 | ||||
-rw-r--r-- | server/src/method/textDocument/definition.lua | 4 | ||||
-rw-r--r-- | server/src/service.lua | 27 |
3 files changed, 95 insertions, 13 deletions
diff --git a/server/src/lsp.lua b/server/src/lsp.lua index 1ac2c6c0..3f804ab4 100644 --- a/server/src/lsp.lua +++ b/server/src/lsp.lua @@ -44,13 +44,29 @@ function mt:_send(data) f(buf) end -function mt:_readAsContent(header) +function mt:_readProtoHead() + local header = self:read 'l' + if not header then + return + end + if header:sub(1, #'Content-Length') == 'Content-Length' then + return header + elseif header:sub(1, #'Content-Type') == 'Content-Type' then + else + log.error('错误的协议头:', header) + end +end + +function mt:_readProtoContent(header) local len = tonumber(header:match('%d+')) if not len then log.error('错误的协议头:', header) return end local buf = self:read(len+2) + if not buf then + return + end local suc, res = pcall(json.decode, buf) if not suc then log.error('错误的协议:', buf) @@ -79,8 +95,38 @@ function mt:_readAsContent(header) if not response then log.error(err or ('没有回应:' .. method)) end - -- 运行时不清理垃圾,在回复前端之后清理垃圾 - collectgarbage() + return true +end + +function mt:_buildTextCache() + if not next(self._need_compile) then + return + end + local list = {} + for uri in pairs(self._need_compile) do + list[#list+1] = uri + end + + local size = 0 + local clock = os.clock() + for _, uri in ipairs(list) do + local obj = self:compileText(uri) + if obj then + size = size + #obj.text + end + end + local passed = os.clock() - clock + log.debug(('\n\z + 语法树缓存完成\n\z + 耗时:[%.3f]秒\n\z + 数量:[%d]\n\z + 总大小:[%.3f]kb\n\z + 速度:[%.3f]kb/s'):format( + passed, + #list, + size / 1000, + size / passed / 1000 + )) end function mt:setInput(input) @@ -139,6 +185,7 @@ function mt:compileText(uri) end obj.ast = ast obj.lines = parser:lines(obj.text) + return obj end function mt:removeText(uri) @@ -150,15 +197,23 @@ function mt:setMethod(method) end function mt:runStep() - local header = self:read 'l' - if not header then + if not self._header then + -- 如果没有协议头,则尝试读一条协议头 + self._header = self:_readProtoHead() + end + if self._header then + -- 如果有协议头,则读取协议内容 + local suc = self:_readProtoContent(self._header) + if suc then + -- 协议内容读取成功后重置 + self._header = nil + self._idle_clock = 0 + end return end - if header:sub(1, #'Content-Length') == 'Content-Length' then - self:_readAsContent(header) - elseif header:sub(1, #'Content-Type') == 'Content-Type' then - else - log.error('错误的协议头:', header) + self._idle_clock = self._idle_clock + 1 + if self._idle_clock == 1000 then + self:_buildTextCache() end end @@ -171,5 +226,7 @@ return function () return setmetatable({ _file = {}, _need_compile = {}, + _header = nil, + _idle_clock = 0, }, mt) end diff --git a/server/src/method/textDocument/definition.lua b/server/src/method/textDocument/definition.lua index f5fb6472..0cffee4a 100644 --- a/server/src/method/textDocument/definition.lua +++ b/server/src/method/textDocument/definition.lua @@ -2,12 +2,12 @@ local parser = require 'parser' local matcher = require 'matcher' return function (lsp, params) + local start_clock = os.clock() local uri = params.textDocument.uri local ast, lines = lsp:loadText(uri) if not ast then return nil, '找不到文件:' .. uri end - local start_clock = os.clock() -- lua是从1开始的,因此都要+1 local position = lines:position(params.position.line + 1, params.position.character + 1) local suc, start, finish = matcher.definition(ast, position, 'utf8') @@ -39,7 +39,7 @@ return function (lsp, params) } local passed_clock = os.clock() - start_clock if passed_clock >= 0.01 then - log.warn(('[转到定义]耗时[%.3f]秒,文件大小[%s]字节'):format(passed_clock, #text)) + log.warn(('[转到定义]耗时[%.3f]秒,文件大小[%s]字节'):format(passed_clock, #lines.buf)) end return response diff --git a/server/src/service.lua b/server/src/service.lua index 9e11d82f..0763a774 100644 --- a/server/src/service.lua +++ b/server/src/service.lua @@ -22,8 +22,33 @@ local function listen(self, input, output) io.output():setvbuf 'no' local session = lsp() + local cache = '' session:setInput(function (mode) - return io.read(mode) + local num = subprocess.peek(io.input()) + if num > 0 then + cache = cache .. io.read(num) + end + if type(mode) == 'number' then + if #cache < mode then + return nil + end + local res = cache:sub(1, mode) + cache = cache:sub(mode + 1) + return res + elseif mode == 'l' then + local pos = cache:find '[\r\n]' + if not pos then + return nil + end + local res = cache:sub(1, pos - 1) + if cache:sub(pos, pos + 1) == '\r\n' then + cache = cache:sub(pos + 2) + else + cache = cache:sub(pos + 1) + end + return res + end + return nil end) session:setOutput(function (buf) io.write(buf) |