diff --git a/README.md b/README.md index ffa0d09..5e4ddce 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,13 @@ As of 2022 these principles are more aspirational than actual. is suboptimally hairy, at least for the moment: Nix makes a wrapper script for the Lua executable that has appropriate `LUA_PATH` and `LUA_CPATH` settings, but it doesn't do the same for kiwmi. +## Connecting to the repl + +If you are using the example rc.fnl, it opens a Unix socket that you +can connect to and interact with a Fennel REPL. I use +[socat](http://www.dest-unreach.org/socat/) for this purpose: + + $ socat - unix-connect:${XDG_RUNTIME_DIR}/kiwmi-repl.wayland-1.socket # TODO diff --git a/rc.fnl b/rc.fnl index 035e2a4..4cda004 100644 --- a/rc.fnl +++ b/rc.fnl @@ -1,7 +1,16 @@ (local { : GdkPixbuf } (require :lgi)) (local { : view } (require :fennel)) +(local socket-repl (require :socket-repl)) +(let [repl-socket-name + (.. + (: (os.getenv "XDG_RUNTIME_DIR") :gsub "/$" "") + "/kiwmi-repl." + (os.getenv "WAYLAND_DISPLAY") + ".socket" + )] + (socket-repl.start repl-socket-name)) (fn texture-from-file [renderer filename] diff --git a/shell.nix b/shell.nix index 09a3d2f..ec2e0c5 100644 --- a/shell.nix +++ b/shell.nix @@ -1,7 +1,7 @@ with import {} ; let p = callPackage ./. {}; in (p.overrideAttrs (o:{ - nativeBuildInputs = [pkgs.gdb]; + nativeBuildInputs = with pkgs; [gdb socat]; shellHook = '' export LUA_PATH=`lua -e 'print(package.path)'` export LUA_CPATH=`lua -e 'print(package.cpath)'` diff --git a/socket-repl.fnl b/socket-repl.fnl new file mode 100644 index 0000000..47f09cc --- /dev/null +++ b/socket-repl.fnl @@ -0,0 +1,52 @@ +(local { : fdopen } (require "posix.stdio")) +(local fcntl (require "posix.fcntl")) +(local unistd (require "posix.unistd")) +(local socket (require "posix.sys.socket")) +(local { : repl } (require :fennel)) + +(fn watch-fd [fd mode handler] + (kiwmi:event_loop_add_fd fd mode handler)) + +(fn unix-socket-listener [pathname on-connected] + (let [sa {:family socket.AF_UNIX + :path pathname + } + fd (socket.socket socket.AF_UNIX socket.SOCK_STREAM 0)] + (socket.bind fd sa) + (socket.listen fd 5) + (watch-fd + fd fcntl.O_RDWR + #(let [connected-fd (socket.accept $1)] + (on-connected connected-fd))) + )) + +(fn start [pathname] + (print pathname) + (unistd.unlink pathname) + (unix-socket-listener + pathname + (fn [fd] + (let [sock (fdopen fd "w+") + repl-coro (coroutine.create repl)] + (print :fd fd :sock sock) + (watch-fd fd fcntl.O_RDONLY + #(coroutine.resume repl-coro (unistd.read $1 1024))) + (coroutine.resume repl-coro + {:readChunk + (fn [{: stack-size}] + (sock:write + (if (> stack-size 0) ".." ">> ")) + (sock:flush) + (coroutine.yield)) + :onValues + (fn [vals] + (sock:write (table.concat vals "\t")) + (sock:write "\n")) + :onError + (fn [errtype err] + (sock:write + (.. errtype " error: " (tostring err) "\n"))) + }))))) + + +{ : start }