summaryrefslogtreecommitdiff
path: root/script-beta
diff options
context:
space:
mode:
Diffstat (limited to 'script-beta')
-rw-r--r--script-beta/await.lua131
-rw-r--r--script-beta/core/completion.lua9
-rw-r--r--script-beta/files.lua4
-rw-r--r--script-beta/proto/proto.lua2
-rw-r--r--script-beta/provider/diagnostic.lua17
-rw-r--r--script-beta/provider/provider.lua2
-rw-r--r--script-beta/pub/report.lua2
-rw-r--r--script-beta/service/service.lua2
-rw-r--r--script-beta/workspace/workspace.lua10
9 files changed, 99 insertions, 80 deletions
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