summaryrefslogtreecommitdiff
path: root/server
diff options
context:
space:
mode:
Diffstat (limited to 'server')
-rw-r--r--server/main.lua1
-rw-r--r--server/src/method/textDocument/references.lua1
-rw-r--r--server/src/service.lua36
-rw-r--r--server/src/timer.lua272
4 files changed, 304 insertions, 6 deletions
diff --git a/server/main.lua b/server/main.lua
index 2f96e7cd..35b75789 100644
--- a/server/main.lua
+++ b/server/main.lua
@@ -11,6 +11,7 @@ collectgarbage('generational')
log = require 'log'
log.init(ROOT, ROOT / 'log' / 'service.log')
log.info('Lua Lsp startup, root: ', ROOT)
+ac = {}
local function tryDebugger()
local dbg = require 'debugger'
diff --git a/server/src/method/textDocument/references.lua b/server/src/method/textDocument/references.lua
index 555808ca..d4478d0e 100644
--- a/server/src/method/textDocument/references.lua
+++ b/server/src/method/textDocument/references.lua
@@ -7,6 +7,7 @@ return function (lsp, params)
if not vm then
return {}
end
+
-- lua是从1开始的,因此都要+1
local position = lines:position(params.position.line + 1, params.position.character + 1)
local positions = core.references(vm, position, declarat)
diff --git a/server/src/service.lua b/server/src/service.lua
index 3b3b4f1d..6c7b83d7 100644
--- a/server/src/service.lua
+++ b/server/src/service.lua
@@ -6,6 +6,7 @@ local rpc = require 'rpc'
local parser = require 'parser'
local core = require 'core'
local lang = require 'language'
+local updateTimer = require 'timer'
local ErrorCodes = {
-- Defined by JSON RPC
@@ -65,6 +66,16 @@ function mt:_callMethod(name, params)
end
end
+function mt:responseProto(id, response, err)
+ local container = table.container()
+ if err then
+ container.error = err
+ else
+ container.result = response
+ end
+ rpc:response(id, container)
+end
+
function mt:_doProto(proto)
local id = proto.id
local name = proto.method
@@ -73,13 +84,13 @@ function mt:_doProto(proto)
if not id then
return
end
- local container = table.container()
- if err then
- container.error = err
+ if type(response) == 'function' then
+ return function (final)
+ self:responseProto(id, final)
+ end
else
- container.result = response
+ self:responseProto(id, response, err)
end
- rpc:response(id, container)
end
function mt:clearDiagnostics(uri)
@@ -111,6 +122,14 @@ function mt:needCompile(uri, compiled)
table.insert(self._needCompile, 1, uri)
end
+function mt:isWaitingCompile()
+ if self._needCompile[1] then
+ return true
+ else
+ return false
+ end
+end
+
function mt:saveText(uri, version, text)
local obj = self._file[uri]
if obj then
@@ -404,7 +423,7 @@ function mt:checkWorkSpaceComplete()
end
function mt:_createCompileTask()
- if not self._needCompile[1] and not next(self._needDiagnostics) then
+ if not self:isWaitingCompile() and not next(self._needDiagnostics) then
return
end
self._compileTask = coroutine.create(function ()
@@ -484,9 +503,14 @@ function mt:listen()
local _, out = async.run 'proto'
self._proto = out
+ local clock = os.clock()
while true do
async.onTick()
self:onTick()
+
+ local delta = os.clock() - clock
+ clock = os.clock()
+ updateTimer(delta)
thread.sleep(0.001)
end
end
diff --git a/server/src/timer.lua b/server/src/timer.lua
new file mode 100644
index 00000000..0ae5094f
--- /dev/null
+++ b/server/src/timer.lua
@@ -0,0 +1,272 @@
+local setmetatable = setmetatable
+local pairs = pairs
+local tableInsert = table.insert
+local mathMax = math.max
+local mathFloor = math.floor
+
+local curFrame = 0
+local maxFrame = 0
+local curIndex = 0
+local freeQueue = {}
+local timer = {}
+
+local function allocQueue()
+ local n = #freeQueue
+ if n > 0 then
+ local r = freeQueue[n]
+ freeQueue[n] = nil
+ return r
+ else
+ return {}
+ end
+end
+
+local function mTimeout(self, timeout)
+ if self._pauseRemaining or self._running then
+ return
+ end
+ local ti = curFrame + timeout
+ local q = timer[ti]
+ if q == nil then
+ q = allocQueue()
+ timer[ti] = q
+ end
+ self._timeoutFrame = ti
+ self._running = true
+ q[#q + 1] = self
+end
+
+local function mWakeup(self)
+ if self._removed then
+ return
+ end
+ self._running = false
+ if self._onTimer then
+ self:_onTimer()
+ end
+ if self._removed then
+ return
+ end
+ if self._timerCount then
+ if self._timerCount > 1 then
+ self._timerCount = self._timerCount - 1
+ mTimeout(self, self._timeout)
+ else
+ self._removed = true
+ end
+ else
+ mTimeout(self, self._timeout)
+ end
+end
+
+local function getRemaining(self)
+ if self._removed then
+ return 0
+ end
+ if self._pauseRemaining then
+ return self._pauseRemaining
+ end
+ if self._timeoutFrame == curFrame then
+ return self._timeout or 0
+ end
+ return self._timeoutFrame - curFrame
+end
+
+local function onTick()
+ local q = timer[curFrame]
+ if q == nil then
+ curIndex = 0
+ return
+ end
+ for i = curIndex + 1, #q do
+ local callback = q[i]
+ curIndex = i
+ q[i] = nil
+ if callback then
+ mWakeup(callback)
+ end
+ end
+ curIndex = 0
+ timer[curFrame] = nil
+ freeQueue[#freeQueue + 1] = q
+end
+
+function ac.clock()
+ return curFrame / 1000.0
+end
+
+function ac.timer_size()
+ local n = 0
+ for _, ts in pairs(timer) do
+ n = n + #ts
+ end
+ return n
+end
+
+function ac.timer_all()
+ local tbl = {}
+ for _, ts in pairs(timer) do
+ for i, t in ipairs(ts) do
+ if t then
+ tbl[#tbl + 1] = t
+ end
+ end
+ end
+ return tbl
+end
+
+local function update(delta)
+ if curIndex ~= 0 then
+ curFrame = curFrame - 1
+ end
+ maxFrame = maxFrame + delta * 1000.0
+ while curFrame < maxFrame do
+ curFrame = curFrame + 1
+ onTick()
+ end
+end
+
+local mt = {}
+mt.__index = mt
+mt.type = 'timer'
+
+function mt:__tostring()
+ return '[table:timer]'
+end
+
+function mt:__call()
+ if self._onTimer then
+ self:_onTimer()
+ end
+end
+
+function mt:remove()
+ self._removed = true
+end
+
+function mt:pause()
+ if self._removed or self._pauseRemaining then
+ return
+ end
+ self._pauseRemaining = getRemaining(self)
+ self._running = false
+ local ti = self._timeoutFrame
+ local q = timer[ti]
+ if q then
+ for i = #q, 1, -1 do
+ if q[i] == self then
+ q[i] = false
+ return
+ end
+ end
+ end
+end
+
+function mt:resume()
+ if self._removed or not self._pauseRemaining then
+ return
+ end
+ local timeout = self._pauseRemaining
+ self._pauseRemaining = nil
+ mTimeout(self, timeout)
+end
+
+function mt:restart()
+ if self._removed or self._pauseRemaining or not self._running then
+ return
+ end
+ local ti = self._timeoutFrame
+ local q = timer[ti]
+ if q then
+ for i = #q, 1, -1 do
+ if q[i] == self then
+ q[i] = false
+ break
+ end
+ end
+ end
+ self._running = false
+ mTimeout(self, self._timeout)
+end
+
+function mt:remaining()
+ return getRemaining(self) / 1000.0
+end
+
+function ac.wait(timeout, onTimer)
+ local t = setmetatable({
+ ['_timeout'] = mathMax(mathFloor(timeout * 1000.0), 1),
+ ['_onTimer'] = onTimer,
+ ['_timerCount'] = 1,
+ }, mt)
+ mTimeout(t, t._timeout)
+ return t
+end
+
+function ac.loop(timeout, onTimer)
+ local t = setmetatable({
+ ['_timeout'] = mathFloor(timeout * 1000.0),
+ ['_onTimer'] = onTimer,
+ }, mt)
+ mTimeout(t, t._timeout)
+ return t
+end
+
+function ac.timer(timeout, count, onTimer)
+ if count == 0 then
+ return ac.loop(timeout, onTimer)
+ end
+ local t = setmetatable({
+ ['_timeout'] = mathFloor(timeout * 1000.0),
+ ['_onTimer'] = onTimer,
+ ['_timerCount'] = count,
+ }, mt)
+ mTimeout(t, t._timeout)
+ return t
+end
+
+local function utimer_initialize(u)
+ if not u._timers then
+ u._timers = {}
+ end
+ if #u._timers > 0 then
+ return
+ end
+ u._timers[1] = ac.loop(0.01, function()
+ local timers = u._timers
+ for i = #timers, 2, -1 do
+ if timers[i]._removed then
+ local len = #timers
+ timers[i] = timers[len]
+ timers[len] = nil
+ end
+ end
+ if #timers == 1 then
+ timers[1]:remove()
+ timers[1] = nil
+ end
+ end)
+end
+
+function ac.uwait(u, timeout, onTimer)
+ utimer_initialize(u)
+ local t = ac.wait(timeout, onTimer)
+ tableInsert(u._timers, t)
+ return t
+end
+
+function ac.uloop(u, timeout, onTimer)
+ utimer_initialize(u)
+ local t = ac.loop(timeout, onTimer)
+ tableInsert(u._timers, t)
+ return t
+end
+
+function ac.utimer(u, timeout, count, onTimer)
+ utimer_initialize(u)
+ local t = ac.timer(timeout, count, onTimer)
+ tableInsert(u._timers, t)
+ return t
+end
+
+return update