Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local expect = require "cc.expect".expect
- local WATCHED_FILENAME = ...
- if not WATCHED_FILENAME then
- error("Usage: watch <filename>", 0)
- end
- --- Returns a function which can be used in parallel to run multiple coroutines
- --- as needed. Two other functions are returned that allow you to add and remove
- --- coroutines whenever needed.
- ---
- ---@return function manager The coroutine manager.
- ---@return fun(name:string, func:fun()|thread) coroutine_add The function that adds coroutines.
- ---@return fun(name:string) coroutine_remove The function that removes coroutines.
- function EditableCoroutine()
- local coroutines = {}
- local filters = {}
- --- Adds a coroutine to be run in the manager.
- ---@param name string The name of the coroutine.
- ---@param func fun()|thread The function to be converted to a coroutine, or a thread.
- local function coroutine_add(name, func)
- expect(1, name, "string")
- expect(2, func, "function", "thread")
- if coroutines[name] then error("A coroutine with that name already exists.", 2) end
- if type(func) == "function" then
- func = coroutine.create(func)
- end
- coroutines[name] = func
- coroutine.resume(func)
- end
- --- Removes a coroutine from the manager.
- ---@param name string The name of the coroutine to be removed.
- local function coroutine_remove(name)
- coroutines[name] = nil
- filters[name] = nil
- end
- --- Coroutine manager.
- local function manager()
- ---@param coro thread The coroutine to resume.
- ---@param name string The coroutine's name.
- ---@param ... any The values to resume with.
- local function resume(coro, name, ...)
- local ok, filter = coroutine.resume(coro, ...)
- -- If the coroutine stopped due to error, throw the error.
- if not ok and filter ~= "cannot resume dead coroutine" then
- error(filter, 0)
- end
- if not ok and filter == "cannot resume dead coroutine" then
- coroutine_remove(name)
- end
- filters[name] = filter
- end
- -- Main coroutine loop
- while true do
- -- Gather the event.
- local event = table.pack(os.pullEvent())
- -- Loop through each coroutine and check if it should be resumed.
- for name, coro in pairs(coroutines) do
- -- If filter is the same
- -- Or if filter is not set (take any event)
- -- Or if the event is a terminate event
- if event[1] == filters[name] or event[1] == "terminate" or not filters[name] then
- resume(coro, name, table.unpack(event, 1, event.n))
- -- If the coroutine finished, remove it.
- if coroutine.status(coro) == "dead" then
- coroutine_remove(name)
- end
- end
- end
- end
- end
- return manager, coroutine_add, coroutine_remove
- end
- local manager, add, remove = EditableCoroutine()
- local function wait_for_reset()
- print "Press f10 to reset."
- repeat
- local _, key = os.pullEvent("key")
- until key == keys.f10
- print "f10 pressed. Restarting in 2 seconds."
- remove("main")
- end
- while true do
- local h, err
- repeat
- h, err = io.open(WATCHED_FILENAME, 'r')
- if not h then
- printError(err)
- sleep(1)
- end
- until h
- local code = h:read("*a")
- h:close()
- print("File read, running it.")
- local loaded, err = load(code, string.format("=%s", WATCHED_FILENAME), "bt", _ENV)
- if loaded then
- add("main", loaded)
- parallel.waitForAny(wait_for_reset, manager)
- else
- printError(err)
- end
- sleep(2)
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement