A fennel REPL for Hammerspoon
The Fennel programming language is one of my favorite programming languages. It gets a lot of things done right:
- Modern syntax (Clojure-like, but better)
- Immutable by default
- Excellent pattern matching
If I ever find myself working with a Lua interpreter (Hammerspoon, Neovim, TIC-80, etc.), Fennel is often my go-to for concise and efficient code.
The question is, can I have a REPL for Hammerspoon? There are multiple options available, like nREPL via jeejah, but I find it limited compared to the REPL that comes with fennel-mode. Hammerspoon does come with an interactive shell, and I would like to adapt it to work with fennel-mode
. In fact, it’s very possible. Hammerspoon comes with a hook, _consoleInputPreparser
, that can be hacked to evaluate an expression. Essentially, we can run a REPL in a coroutine and resume it whenever the user inputs something.
(require :hs.ipc)
(local fennel (require :fennel))
(let [coro (coroutine.create fennel.repl)]
(coroutine.resume coro {:readChunk (fn []
(let [input (coroutine.yield)]
(.. input "\n")))
:onValues (fn [xs]
(print (table.concat xs "\t")))
:onError (fn [_ msg]
(print msg))})
(set hs._consoleInputPreparser (fn [s]
(coroutine.resume coro s)
"")))
Here is the result:
And of course, you can evaluate code and get completion with fennel-mode
, too.