1+ local Util = require (" lazy.core.util" )
2+
13local M = {}
24
35--- @type Async[]
4- M ._queue = {}
5- M ._executor = assert (vim .loop .new_timer ())
6+ M ._active = {}
7+ --- @type Async[]
8+ M ._suspended = {}
9+ M ._executor = assert (vim .loop .new_check ())
610
7- M .TIMER = 10
8- M .BUDGET = 100
11+ M .BUDGET = 10
912
1013--- @type table<thread , Async>
1114M ._threads = setmetatable ({}, { __mode = " k" })
@@ -42,11 +45,6 @@ function Async:init(fn)
4245 return M .add (self )
4346end
4447
45- function Async :restart ()
46- assert (not self :running (), " Cannot restart a running async" )
47- self :init (self ._fn )
48- end
49-
5048--- @param event AsyncEvent
5149--- @param cb async fun ( res : any , async : Async )
5250function Async :on (event , cb )
@@ -77,27 +75,41 @@ function Async:sleep(ms)
7775end
7876
7977--- @async
80- function Async :suspend ()
78+ --- @param yield ? boolean
79+ function Async :suspend (yield )
8180 self ._suspended = true
82- if coroutine.running () == self ._co then
81+ if coroutine.running () == self ._co and yield ~= false then
8382 coroutine.yield ()
8483 end
8584end
8685
8786function Async :resume ()
8887 self ._suspended = false
88+ M ._run ()
8989end
9090
91- function Async :wait ()
91+ --- @async
92+ --- @param yield ? boolean
93+ function Async :wake (yield )
9294 local async = M .running ()
95+ assert (async , " Not in an async context" )
96+ self :on (" done" , function ()
97+ async :resume ()
98+ end )
99+ async :suspend (yield )
100+ end
101+
102+ --- @async
103+ function Async :wait ()
93104 if coroutine.running () == self ._co then
94105 error (" Cannot wait on self" )
95106 end
96107
97- while self :running () do
98- if async then
99- coroutine.yield ()
100- else
108+ local async = M .running ()
109+ if async then
110+ self :wake ()
111+ else
112+ while self :running () do
101113 vim .wait (10 )
102114 end
103115 end
@@ -121,33 +133,42 @@ function Async:step()
121133end
122134
123135function M .step ()
124- local budget = M .BUDGET * 1e6
125136 local start = vim .uv .hrtime ()
126- local count = # M ._queue
127- local i = 0
128- while # M ._queue > 0 and vim .uv .hrtime () - start < budget do
129- --- @type Async
130- local state = table.remove (M ._queue , 1 )
131- if state :step () then
132- table.insert (M ._queue , state )
133- end
134- i = i + 1
135- if i >= count then
137+ for _ = 1 , # M ._active do
138+ if vim .uv .hrtime () - start > M .BUDGET * 1e6 then
136139 break
137140 end
141+ local state = table.remove (M ._active , 1 )
142+ if state :step () then
143+ if state ._suspended then
144+ table.insert (M ._suspended , state )
145+ else
146+ table.insert (M ._active , state )
147+ end
148+ end
138149 end
139- if # M ._queue == 0 then
150+ for _ = 1 , # M ._suspended do
151+ local state = table.remove (M ._suspended , 1 )
152+ table.insert (state ._suspended and M ._suspended or M ._active , state )
153+ end
154+
155+ -- print("step", #M._active, #M._suspended)
156+ if # M ._active == 0 then
140157 return M ._executor :stop ()
141158 end
142159end
143160
144161--- @param async Async
145162function M .add (async )
146- table.insert (M ._queue , async )
163+ table.insert (M ._active , async )
164+ M ._run ()
165+ return async
166+ end
167+
168+ function M ._run ()
147169 if not M ._executor :is_active () then
148- M ._executor :start (1 , M . TIMER , vim .schedule_wrap (M .step ))
170+ M ._executor :start (vim .schedule_wrap (M .step ))
149171 end
150- return async
151172end
152173
153174function M .running ()
0 commit comments