Advertisement
fatboychummy

watcher.lua

Mar 28th, 2023
538
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 3.52 KB | Software | 0 0
  1. local expect = require "cc.expect".expect
  2.  
  3. local WATCHED_FILENAME = ...
  4. if not WATCHED_FILENAME then
  5.   error("Usage: watch <filename>", 0)
  6. end
  7.  
  8. --- Returns a function which can be used in parallel to run multiple coroutines
  9. --- as needed. Two other functions are returned that allow you to add and remove
  10. --- coroutines whenever needed.
  11. ---
  12. ---@return function manager The coroutine manager.
  13. ---@return fun(name:string, func:fun()|thread) coroutine_add The function that adds coroutines.
  14. ---@return fun(name:string) coroutine_remove The function that removes coroutines.
  15. function EditableCoroutine()
  16.   local coroutines = {}
  17.   local filters = {}
  18.  
  19.   --- Adds a coroutine to be run in the manager.
  20.   ---@param name string The name of the coroutine.
  21.   ---@param func fun()|thread The function to be converted to a coroutine, or a thread.
  22.   local function coroutine_add(name, func)
  23.     expect(1, name, "string")
  24.     expect(2, func, "function", "thread")
  25.     if coroutines[name] then error("A coroutine with that name already exists.", 2) end
  26.  
  27.     if type(func) == "function" then
  28.       func = coroutine.create(func)
  29.     end
  30.  
  31.  
  32.     coroutines[name] = func
  33.  
  34.     coroutine.resume(func)
  35.   end
  36.  
  37.   --- Removes a coroutine from the manager.
  38.   ---@param name string The name of the coroutine to be removed.
  39.   local function coroutine_remove(name)
  40.     coroutines[name] = nil
  41.     filters[name] = nil
  42.   end
  43.  
  44.   --- Coroutine manager.
  45.   local function manager()
  46.     ---@param coro thread The coroutine to resume.
  47.     ---@param name string The coroutine's name.
  48.     ---@param ... any The values to resume with.
  49.     local function resume(coro, name, ...)
  50.       local ok, filter = coroutine.resume(coro, ...)
  51.  
  52.       -- If the coroutine stopped due to error, throw the error.
  53.       if not ok and filter ~= "cannot resume dead coroutine" then
  54.         error(filter, 0)
  55.       end
  56.  
  57.       if not ok and filter == "cannot resume dead coroutine" then
  58.         coroutine_remove(name)
  59.       end
  60.  
  61.       filters[name] = filter
  62.     end
  63.  
  64.     -- Main coroutine loop
  65.     while true do
  66.       -- Gather the event.
  67.       local event = table.pack(os.pullEvent())
  68.  
  69.       -- Loop through each coroutine and check if it should be resumed.
  70.       for name, coro in pairs(coroutines) do
  71.         -- If filter is the same
  72.         -- Or if filter is not set (take any event)
  73.         -- Or if the event is a terminate event
  74.         if event[1] == filters[name] or event[1] == "terminate" or not filters[name] then
  75.           resume(coro, name, table.unpack(event, 1, event.n))
  76.  
  77.           -- If the coroutine finished, remove it.
  78.           if coroutine.status(coro) == "dead" then
  79.             coroutine_remove(name)
  80.           end
  81.         end
  82.       end
  83.     end
  84.   end
  85.  
  86.   return manager, coroutine_add, coroutine_remove
  87. end
  88.  
  89. local manager, add, remove = EditableCoroutine()
  90.  
  91. local function wait_for_reset()
  92.   print "Press f10 to reset."
  93.  
  94.   repeat
  95.     local _, key = os.pullEvent("key")
  96.   until key == keys.f10
  97.  
  98.   print "f10 pressed. Restarting in 2 seconds."
  99.   remove("main")
  100. end
  101.  
  102. while true do
  103.   local h, err
  104.   repeat
  105.     h, err = io.open(WATCHED_FILENAME, 'r')
  106.     if not h then
  107.       printError(err)
  108.       sleep(1)
  109.     end
  110.   until h
  111.  
  112.   local code = h:read("*a")
  113.   h:close()
  114.  
  115.   print("File read, running it.")
  116.   local loaded, err = load(code, string.format("=%s", WATCHED_FILENAME), "bt", _ENV)
  117.   if loaded then
  118.     add("main", loaded)
  119.     parallel.waitForAny(wait_for_reset, manager)
  120.   else
  121.     printError(err)
  122.   end
  123.  
  124.   sleep(2)
  125. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement