diff --git a/lib/stdio.fnl b/lib/stdio.fnl index c26810a..9135c85 100644 --- a/lib/stdio.fnl +++ b/lib/stdio.fnl @@ -1,29 +1,24 @@ (require "love.event") -(local {: view} (require :lib.fennel)) ;; This module exists in order to expose stdio over a channel so that it ;; can be used in a non-blocking way from another thread. -(local (event channel) ...) +(fn prompt [cont?] + (io.write (if cont? ".." ">> ")) (io.flush) (.. (io.read) "\n")) -(fn prompt [next-line?] - (io.write (if next-line? ".." ">> ")) (io.flush) (.. (io.read) "\n")) +;; This module is loaded twice: initially in the main thread where ... is nil, +;; and then again in a separate thread where ... contains the channel used to +;; communicate with the main thread. -(when channel - ((fn looper [input] - (when input - ;; This is consumed by love.handlers[event] - (love.event.push event input) - (let [output (: channel :demand) - next-line (and (. output 2) (= "next-line" (. output 2)))] - ;; There is probably a more efficient way of determining an error - (if next-line :ok - (and (. output 2) (= "Error:" (. output 2))) - (print (view output)) - (each [_ ret (ipairs output)] - (print ret))) - (io.flush) - (looper (prompt next-line))))) (prompt))) +(fn looper [event channel] + (match (channel:demand) + [:write vals] (do (io.write (table.concat vals "\t")) + (io.write "\n")) + [:read cont?] (love.event.push event (prompt cont?))) + (looper event channel)) + +(match ... + (event channel) (looper event channel)) {:start (fn start-repl [] (let [code (love.filesystem.read "lib/stdio.fnl") @@ -34,19 +29,17 @@ thread (love.thread.newThread luac) io-channel (love.thread.newChannel) coro (coroutine.create fennel.repl) - out (fn [val] - (: io-channel :push val)) - options {:readChunk (fn [parser-state] - (when (> parser-state.stack-size 0) - (: io-channel :push ["next-line" "next-line"])) + options {:readChunk (fn [{: stack-size}] + (io-channel:push [:read (< 0 stack-size)]) (coroutine.yield)) - :onValues out - :onError (fn [kind ...] (out [kind "Error:" ...])) - :pp view + :onValues (fn [vals] + (io-channel:push [:write vals])) + :onError (fn [errtype err] + (io-channel:push [:write [err]])) :moduleName "lib.fennel"}] ;; this thread will send "eval" events for us to consume: (coroutine.resume coro options) - (: thread :start "eval" io-channel) + (thread:start "eval" io-channel) (set love.handlers.eval (fn [input] - (coroutine.resume coro input)))))} + (coroutine.resume coro input)))))}