add socket repl

main
Daniel Barlow 2022-12-21 21:51:06 +00:00
parent 512e8cad2f
commit 4cb82c8ca6
5 changed files with 90 additions and 1 deletions

2
.dir-locals.el Normal file
View File

@ -0,0 +1,2 @@
((fennel-mode .
((inferior-lisp-program . "./repl.sh"))))

View File

@ -28,9 +28,19 @@
nix-shell$ overmind connect
</pre>
This starts a fennel interpreter and a test runner in tmux windows.
This starts a Fennel interpreter and a test runner in tmux windows.
Use <pre>C-b n</pre> to switch between them or <pre>C-b d</pre>
to detach.
<pre>
$ fennel dunlin.fnl &
$ ./repl.sh
</pre>
Dunlin will open a socket in <tt>$XDG_RUNTIME_DIR</tt> to allow
communication with a Fennel REPL. The <tt>repl.sh</tt> script
uses <a href="http://www.dest-unreach.org/socat/">socat</a>
to connect to it.
</html>

View File

@ -10,4 +10,8 @@
(f:show-buffer b)
(b:visit (.. "file://" (lfs.currentdir) "/doc/index.html")))
(let [socketdir (or (os.getenv "XDG_RUNTIME_DIR") (os.getenv "HOME"))]
((. (require :socket-repl) :start)
(.. socketdir "/dunlin.sock")))
(Gtk.main)

2
repl.sh Executable file
View File

@ -0,0 +1,2 @@
#!/usr/bin/env nix-shell
#! nix-shell -p socat --run "socat - unix-connect:${XDG_RUNTIME_DIR-$HOME}/dunlin.sock"

71
socket-repl.fnl Normal file
View File

@ -0,0 +1,71 @@
(local { : fdopen } (require "posix.stdio"))
(local fcntl (require "posix.fcntl"))
(local unistd (require "posix.unistd"))
(local socket (require "posix.sys.socket"))
(local lgi (require :lgi))
(local { : GLib } lgi)
(local { : repl } (require :fennel))
(fn watch-fd [fd mode handler]
(let [events [ GLib.IOCondition.IN GLib.IOCondition.HUP]
channel (GLib.IOChannel.unix_new fd)]
(GLib.io_add_watch channel 0 events #(handler fd))))
(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 get-input [fd]
(let [buf (unistd.read fd 1024)]
(if (and buf (> (# buf) 0))
buf
"\n,exit")))
(fn start [pathname]
(unistd.unlink pathname)
(unix-socket-listener
pathname
(fn [fd]
(let [sock (fdopen fd "w+")
repl-coro (coroutine.create repl)]
(watch-fd fd fcntl.O_RDONLY
(fn [fd]
(coroutine.resume repl-coro (get-input fd))
(if (= (coroutine.status repl-coro) :dead)
(do
(sock:write "bye!\n")
(sock:close)
false)
true
)))
(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 }