@@ -202,4 +202,154 @@ function utils.get_os_command_output(cmd)
202202 return Job :new ({ command = command , args = cmd }):sync ()
203203end
204204
205+ local uv = vim .loop
206+ local co = coroutine
207+
208+ local Executor = {}
209+ Executor .__index = Executor
210+
211+ function Executor .new (opts )
212+ opts = opts or {}
213+
214+ local self = setmetatable ({}, Executor )
215+
216+ self .tasks = opts .tasks or {}
217+ self .mode = opts .mode or " next"
218+ self .index = opts .start_idx or 1
219+ self .idle = uv .new_idle ()
220+
221+ return self
222+ end
223+
224+ function Executor :run ()
225+ self .idle :start (vim .schedule_wrap (function ()
226+ if # self .tasks == 0 then
227+ self .idle :stop ()
228+ return
229+ end
230+
231+ if self .mode == " finish" then
232+ self :step_finish ()
233+ else
234+ self :step ()
235+ end
236+ end ))
237+ end
238+
239+ function Executor :close ()
240+ self .idle :stop ()
241+ self .tasks = {}
242+ end
243+
244+ function Executor :step_finish ()
245+ if # self .tasks == 0 then return end
246+ local curr_task = self .tasks [self .index ]
247+ if curr_task == nil then
248+ self .index = 1
249+ curr_task = self .tasks [self .index ]
250+ end
251+
252+ local _ , _ = co .resume (curr_task )
253+ if co .status (curr_task ) == " dead" then
254+ table.remove (self .tasks , self .index )
255+
256+ self .index = self .index + 1
257+ end
258+ end
259+
260+ function Executor :step ()
261+ if # self .tasks == 0 then return end
262+ local curr_task = self .tasks [self .index ]
263+ if curr_task == nil then
264+ self .index = 1
265+ curr_task = self .tasks [self .index ]
266+ end
267+
268+ local _ , _ = co .resume (curr_task [1 ], unpack (curr_task [2 ]))
269+ if co .status (curr_task [1 ]) == " dead" then
270+ table.remove (self .tasks , self .index )
271+ end
272+
273+ self .index = self .index + 1
274+ end
275+
276+ function Executor :get_current_task ()
277+ return self .tasks [self .index ]
278+ end
279+
280+ function Executor :remove_task (idx )
281+ table.remove (self .tasks , idx )
282+ end
283+
284+ function Executor :add (task , ...)
285+ table.insert (self .tasks , {task , {... }})
286+ end
287+
288+ utils .Executor = Executor
289+
290+ List = {}
291+
292+ function List .new ()
293+ return {first = 0 , last = - 1 }
294+ end
295+
296+ function List .pushleft (list , value )
297+ local first = list .first - 1
298+ list .first = first
299+ list [first ] = value
300+ end
301+
302+ function List .pushright (list , value )
303+ local last = list .last + 1
304+ list .last = last
305+ list [last ] = value
306+ end
307+
308+ function List .popleft (list )
309+ local first = list .first
310+ if first > list .last then return nil end
311+ local value = list [first ]
312+ list [first ] = nil -- to allow garbage collection
313+ list .first = first + 1
314+ return value
315+ end
316+
317+ function List .is_empty (list )
318+ return list .first > list .last
319+ end
320+
321+ function List .popright (list )
322+ local last = list .last
323+ if list .first > last then return nil end
324+ local value = list [last ]
325+ list [last ] = nil -- to allow garbage collection
326+ list .last = last - 1
327+ return value
328+ end
329+
330+ function List .len (list )
331+ return list .last - list .first
332+ end
333+
334+ utils .List = List
335+
336+ function successive_async (f )
337+ local list = List .new ()
338+
339+ local function wrapped (...)
340+ if list == nil then return end
341+ -- if List.is_empty(list) or list == nil then return end
342+
343+ List .pushleft (list , {... })
344+ local curr = List .popright (list )
345+ f (unpack (curr ))
346+ end
347+
348+ local function finish ()
349+ list = nil
350+ end
351+
352+ return wrapped
353+ end
354+
205355return utils
0 commit comments