diff options
-rw-r--r-- | .vscode/launch.json | 2 | ||||
-rw-r--r-- | debugger.lua | 2 | ||||
-rw-r--r-- | script-beta/await.lua | 131 | ||||
-rw-r--r-- | script-beta/core/completion.lua | 9 | ||||
-rw-r--r-- | script-beta/files.lua | 4 | ||||
-rw-r--r-- | script-beta/proto/proto.lua | 2 | ||||
-rw-r--r-- | script-beta/provider/diagnostic.lua | 17 | ||||
-rw-r--r-- | script-beta/provider/provider.lua | 2 | ||||
-rw-r--r-- | script-beta/pub/report.lua | 2 | ||||
-rw-r--r-- | script-beta/service/service.lua | 2 | ||||
-rw-r--r-- | script-beta/workspace/workspace.lua | 10 |
11 files changed, 101 insertions, 82 deletions
diff --git a/.vscode/launch.json b/.vscode/launch.json index 838f6b24..5095cfb2 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -48,7 +48,7 @@ "type": "lua", "request": "attach", "stopOnEntry": true, - "address": "127.0.0.1:11413", + "address": "127.0.0.1:11414", "outputCapture": [ ] }, diff --git a/debugger.lua b/debugger.lua index b89be34a..151efc70 100644 --- a/debugger.lua +++ b/debugger.lua @@ -53,7 +53,7 @@ local function tryDebugger() log.debug('Debugger startup, listen port:', DBGPORT) log.debug('Debugger args:', addr, root, path, cpath) if DBGWAIT then - dbg:wait() + dbg:event('wait') end return dbg end diff --git a/script-beta/await.lua b/script-beta/await.lua index ff45a141..b8c6ac17 100644 --- a/script-beta/await.lua +++ b/script-beta/await.lua @@ -1,12 +1,12 @@ -local timer = require 'timer' +local timer = require 'timer' +local util = require 'utility' ---@class await local m = {} m.type = 'await' -m.coTracker = setmetatable({}, { __mode = 'k' }) -m.coPriority = setmetatable({}, { __mode = 'k' }) -m.coDelayer = setmetatable({}, { __mode = 'k' }) +m.coMap = setmetatable({}, { __mode = 'k' }) +m.idMap = {} m.delayQueue = {} m.delayQueueIndex = 1 @@ -25,40 +25,85 @@ function m.checkResult(co, ...) end --- 创建一个任务 -function m.create(callback, ...) +function m.call(callback, ...) local co = coroutine.create(callback) - m.coTracker[co] = true - return m.checkResult(co, coroutine.resume(co, ...)) + local closers = {} + m.coMap[co] = { + closers = closers, + priority = false, + } + for i = 1, select('#', ...) do + local id = select(i, ...) + if not id then + break + end + m.setID(id, co) + end + + local currentCo = coroutine.running() + local current = m.coMap[currentCo] + if current then + for closer in pairs(current.closers) do + closers[closer] = true + closer(co) + end + end + return m.checkResult(co, coroutine.resume(co)) end ---- 对当前任务设置一个延迟检查器,当延迟前后检查器的返回值不同时,放弃此任务 -function m.setDelayer(callback) - local co = coroutine.running() - m.coDelayer[co] = callback +--- 创建一个任务,并挂起当前线程,当任务完成后再延续当前线程/若任务被关闭,则返回nil +function m.await(callback, ...) + return m.wait(function (waker, ...) + m.call(function () + local returnNil <close> = util.defer(waker) + waker(callback()) + end, ...) + end, ...) +end + +--- 设置一个可继承的关闭器,在设置时,以及创建子协程时会调用 +function m.setCloser(callback, co) + co = co or coroutine.running() + local current = m.coMap[co] + current[callback] = true + callback(co) +end + +--- 设置一个id,用于批量关闭任务 +function m.setID(id, co) + co = co or coroutine.running() + if not m.idMap[id] then + m.idMap[id] = setmetatable({}, { __mode = 'k' }) + end + m.idMap[id][co] = true +end + +--- 根据id批量关闭任务 +function m.close(id) + local map = m.idMap[id] + if not map then + return + end + for co in pairs(map) do + map[co] = nil + coroutine.close(co) + end end --- 休眠一段时间 ---@param time number -function m.sleep(time, getVersion) +function m.sleep(time) if not coroutine.isyieldable() then if m.errorHandle then m.errorHandle(debug.traceback('Cannot yield')) end return end - local version = getVersion and getVersion() local co = coroutine.running() - local delayer = m.coDelayer[co] - local dVersion = delayer and delayer() timer.wait(time, function () - if version == (getVersion and getVersion()) - and dVersion == (delayer and delayer()) then - return m.checkResult(co, coroutine.resume(co)) - else - coroutine.close(co) - end + return m.checkResult(co, coroutine.resume(co)) end) - return coroutine.yield(getVersion) + return coroutine.yield() end --- 等待直到唤醒 @@ -68,51 +113,37 @@ function m.wait(callback, ...) return end local co = coroutine.running() + local waked callback(function (...) + if waked then + return + end + waked = true return m.checkResult(co, coroutine.resume(co, ...)) - end) - return coroutine.yield(...) + end, ...) + return coroutine.yield() end --- 延迟 -function m.delay(getVersion) +function m.delay() if not coroutine.isyieldable() then return end local co = coroutine.running() + local current = m.coMap[co] -- TODO - if m.coPriority[co] then + if current.priority then return end - local version = getVersion and getVersion() - local delayer = m.coDelayer[co] - local dVersion = delayer and delayer() m.delayQueue[#m.delayQueue+1] = function () - if version == (getVersion and getVersion()) - and dVersion == (delayer and delayer()) then - return m.checkResult(co, coroutine.resume(co)) - else - coroutine.close(co) + if coroutine.status(co) ~= 'suspended' then + return end + return m.checkResult(co, coroutine.resume(co)) end return coroutine.yield() end -local function getCo(waker) - local co - for i = 1, 100 do - local n, v = debug.getupvalue(waker, i) - if not n then - return nil - end - if n == 'co' then - co = v - break - end - end - return co -end - --- 步进 function m.step() local waker = m.delayQueue[m.delayQueueIndex] @@ -134,7 +165,7 @@ function m.step() end function m.setPriority(n) - m.coPriority[coroutine.running()] = n + m.coMap[coroutine.running()].priority = true end return m diff --git a/script-beta/core/completion.lua b/script-beta/core/completion.lua index 4df1be5b..c8755b5e 100644 --- a/script-beta/core/completion.lua +++ b/script-beta/core/completion.lua @@ -21,7 +21,6 @@ local furi = require 'file-uri' local rpath = require 'workspace.require-path' local stackID = 0 -local resolveID = 0 local stacks = {} local function stack(callback) stackID = stackID + 1 @@ -38,12 +37,10 @@ local function resolveStack(id) if not callback then return nil end + -- 当进行新的 resolve 时,放弃当前的 resolve - resolveID = resolveID + 1 - await.setDelayer(function () - return resolveID - end) - return callback() + await.close('completion.resove') + return await.await(callback, 'completion.resove') end local function trim(str) diff --git a/script-beta/files.lua b/script-beta/files.lua index 3d1a2c90..30dd52b4 100644 --- a/script-beta/files.lua +++ b/script-beta/files.lua @@ -5,6 +5,7 @@ local furi = require 'file-uri' local parser = require 'parser' local proto = require 'proto' local lang = require 'language' +local await = require 'await' local m = {} @@ -88,6 +89,7 @@ function m.setText(uri, text) file.cache = {} file.version = file.version + 1 m.globalVersion = m.globalVersion + 1 + await.close('files.version') m.onWatch('update', originUri) end @@ -131,12 +133,14 @@ function m.remove(uri) m.fileMap[uri] = nil m.globalVersion = m.globalVersion + 1 + await.close('files.version') m.onWatch('remove', originUri) end --- 移除所有文件 function m.removeAll() m.globalVersion = m.globalVersion + 1 + await.close('files.version') for uri in pairs(m.fileMap) do m.fileMap[uri] = nil m.onWatch('remove', uri) diff --git a/script-beta/proto/proto.lua b/script-beta/proto/proto.lua index 7423cf96..05749815 100644 --- a/script-beta/proto/proto.lua +++ b/script-beta/proto/proto.lua @@ -90,7 +90,7 @@ function m.doMethod(proto) end return end - await.create(function () + await.call(function () --log.debug('Start method:', method) local clock = os.clock() local ok = true diff --git a/script-beta/provider/diagnostic.lua b/script-beta/provider/diagnostic.lua index 7bc8022a..1a6537f8 100644 --- a/script-beta/provider/diagnostic.lua +++ b/script-beta/provider/diagnostic.lua @@ -9,7 +9,6 @@ local util = require 'utility' local m = {} m._start = false -m._diagID = 0 m.cache = {} local function concat(t, sep) @@ -178,32 +177,26 @@ function m.refresh(uri) if not m._start then return end - await.create(function () + await.call(function () -- 一旦文件的版本发生变化,就放弃这次诊断 - await.setDelayer(function () - return files.getVersion(uri) - end) await.delay() if uri then m.doDiagnostic(uri) end m.diagnosticsAll() - end) + end, 'files.version') end function m.diagnosticsAll() - await.create(function () - m._diagID = m._diagID + 1 - await.setDelayer(function () - return m._diagID - end) + await.close 'diagnosticsAll' + await.call(function () local clock = os.clock() for uri in files.eachFile() do await.delay() m.doDiagnostic(uri) end log.debug('全文诊断耗时:', os.clock() - clock) - end) + end, 'files.version', 'diagnosticsAll') end function m.start() diff --git a/script-beta/provider/provider.lua b/script-beta/provider/provider.lua index d908e917..07ecae1f 100644 --- a/script-beta/provider/provider.lua +++ b/script-beta/provider/provider.lua @@ -100,7 +100,7 @@ proto.on('initialized', function (params) } } }) - await.create(workspace.awaitPreload) + await.call(workspace.awaitPreload) return true end) diff --git a/script-beta/pub/report.lua b/script-beta/pub/report.lua index 34f58277..66f3fca8 100644 --- a/script-beta/pub/report.lua +++ b/script-beta/pub/report.lua @@ -11,7 +11,7 @@ end) pub.on('proto', function (params) local proto = require 'proto' - await.create(function () + await.call(function () if params.method then proto.doMethod(params) else diff --git a/script-beta/service/service.lua b/script-beta/service/service.lua index f8a2d761..3f0005ad 100644 --- a/script-beta/service/service.lua +++ b/script-beta/service/service.lua @@ -56,7 +56,7 @@ function m.reportTask() local normal = 0 local dead = 0 - for co in pairs(await.coTracker) do + for co in pairs(await.coMap) do total = total + 1 local status = coroutine.status(co) if status == 'running' then diff --git a/script-beta/workspace/workspace.lua b/script-beta/workspace/workspace.lua index f837fe91..0552bf98 100644 --- a/script-beta/workspace/workspace.lua +++ b/script-beta/workspace/workspace.lua @@ -13,7 +13,6 @@ local m = {} m.type = 'workspace' m.ignoreVersion = -1 m.ignoreMatcher = nil -m.preloadVersion = 0 m.uri = '' m.path = '' m.requireCache = {} @@ -202,15 +201,10 @@ function m.getRelativePath(uri) end function m.reload() - m.preloadVersion = m.preloadVersion + 1 files.removeAll() rpath.flush() - await.create(function () - await.setDelayer(function () - return m.preloadVersion - end) - m.awaitPreload() - end) + await.close 'preload' + await.call(m.awaitPreload, 'preload') end return m |