honeylisp/link/nrepl.fnl

112 lines
3.6 KiB
Fennel

(local core (require :core))
(local socket (require :socket))
(local bencode (require :lib.bencode))
(local lume (require :lib.lume))
(fn contains? [tbl item]
(or (= tbl item) (lume.find tbl item)))
(local nrepl
{:active-requests {}
:session-handlers {}
:default-handlers
{:out #(core.log $2)
:value #(core.log $2)
:ex #(core.err $2)
:status/interrupted #($1:done $3.id)
:status/done #($1:done $3.id)}
:merge-handlers
(fn [self message]
(lume.merge self.default-handlers
(or (. self.session-handlers message.session) {})
(or (. self.active-requests message.id) {})))
:chain-handlers
(fn [self keys ...]
(local new-handlers {})
(each [_ key (ipairs keys)]
(each [_ handlers (ipairs [self.default-handlers ...])]
(local next-handler (. handlers key))
(local prev-handler (. new-handlers key))
(if (and next-handler prev-handler)
(tset new-handlers key
#(do (prev-handler $1 $2 $3) (next-handler $1 $2 $3)))
next-handler
(tset new-handlers key next-handler))))
new-handlers)
:counter 1
:input ""
:parse-input
(fn [self]
(match (pcall #(bencode.decode self.input))
(true val len)
(do (set self.input (self.input:sub (+ len 1)))
val)
(false :Incomplete) nil
(false _)
(do (set self.input "")
nil)))
:receive
(fn [self]
(when self.connection
(local (data err part) (self.connection:receive "*a"))
(local response (or data part))
(when (> (response:len) 0)
(set self.input (.. self.input response)))
(match (self:parse-input) nil nil
input (self:handle input))
(when (= err :closed)
(self:disconnect))))
:send
(fn [self msg ?handlers ?session]
(when self.connection
(when (not msg.id)
(set msg.id self.counter)
(set self.counter (+ self.counter 1)))
(when (not msg.session)
(set msg.session (or ?session self.default-session)))
(when ?handlers
(tset self.active-requests msg.id ?handlers))
(self.connection:send (bencode.encode msg))))
:done
(fn [self msg-id]
(tset self.active-requests msg-id nil))
:handle
(fn [self response]
(pp response)
(local handlers (self:merge-handlers response))
(each [prop handler (pairs handlers)]
(local idiv (prop:find :/))
(local key (if idiv (prop:sub 1 (- idiv 1)) prop))
(when (and (. response key)
(or (= idiv nil)
(contains? (. response key) (prop:sub (+ idiv 1)))))
(handler self (. response key) response))))
:disconnect
(fn [self]
(when self.connection
(self.connection:close)
(set self.connection nil)
(set self.default-session nil)
(set self.active-requests {})
(set self.session-handlers {})))
:connect
(fn [self ?port ?host]
(when (not self.connection)
(local (port host) (values (or ?port 7888) (or ?host :localhost)))
(set self.connection (assert (socket.connect host port)))
(self.connection:settimeout 0)
(core.add_thread #(while true (self:receive) (coroutine.yield)) self)
(self:send {:op :clone}
{:new-session #(set self.default-session $2)})))
:connected?
(fn [self] (not= self.default-session nil))
:new-session
(fn [self callback ?handler]
(self:send {:op :clone}
{:new-session
(fn [self session message]
(tset self.session-handlers session ?handler)
(callback self session message))}))})
nrepl