Fork me on GitHub
#babashka-sci-dev
<
2023-04-20
>
borkdude19:04:03

@benjamin.schwerdtner Worked on the PR you started all day, it was a bit confusing :) There were a few things: metadata contains vars, not just symbols, I think? And comparing the vars from the host to the vars from SCI: this needed a deref, since they represent the same thing, but are not the same vars. • There are a few things left I think. In cider NREPL the :expects and :requires can be either vars or strings denoting "ops". I think it's nicer to not expose the middleware namespace directly but work with those string names and document those. (See https://github.com/clojure-emacs/cider-nrepl/blob/d219ce610d9030108c273fab933538fb3b24d8be/src/cider/nrepl.clj#L111) • See if we can really port one of the existing CIDER middlewares easily using the current state of things

Benjamin19:04:57

This is my current agenda: 1. Try a few versions with either adapting xform middleware to handler style, or modifying to handler style 2. Use the :nrepl.middleware/descriptor metadata to build the middleware deps graph (:expects, :requires etc.). 3. ? Split nrepl.transport protocols and make a sci nrepl Transport Is it a matter of assoc'ing to the response? 4. Load the cider inspector middleware 5. run bb with inspector middleware

borkdude19:04:35

What do you mean with "adapting xform middleware to handler style"

borkdude19:04:45

vs "modifying to handler style"

Benjamin19:04:48

adapting would be using xform under the hood and having a layer that adapts handlers. It would need a bit of work to make :expects etc work. I consider middleware->transducer part of this layer already. Modifying to handler style would be to not use xforms anymore, or to not use them for user middleware.

borkdude19:04:01

1a Yes, that's what's currently merged already right. 1b right, we could rewrite to handler style everything and drop the xforms OR support both, but mutually exlusively to not break existing users (cc @U7RJTCH6J) Another option: 1c is to ask users to write in xform style. Either way, I think we should not expose :ctx :msg :opts to users, but only :msg directly. The :ctx is an implementation detail of SCI which should never be visible to bb users.

✍️ 2
borkdude19:04:57

2. The sorting logic is already pretty much there, based on :expects and :requires logic. But I think 1 is the most important in terms of "what route should we go next", so let's chew on that first

Benjamin19:04:50

- supporting handler style is maybe nice for existing middleware? (on the other hand I don't know who has custom middleware and not the grit to adapt it to an xform style - for bb support) - we should support the current way, for backwards compat - transducers are cool :) - middleware->transducer already works. It might be easy to adapt it a bit to support the nrepl.middleware descriptor keys. - Maybe there is a way to be able to handle both forms, so users can write xforms I go sleep 🙂

👍 2
Benjamin11:04:28

The current state of this is that I was thinking about what it would take to copy the cider nrepl code and write an inspect.clj. I ran into the trouble that transport in nrepl middleware has a different contract from our transformation paradigm. Transport basically allows you to send and receive from within the middleware. But our paradigm is a pure transformation stack, that decides to return (one or many, or filters) responses. It would also go into not only forking cider-nrepl but also nrepl which seems daunting. I stopped until I have an idea for this. I could try building an inspect.clj without using any nrepl middleware utils etc. Might be straightforward.

borkdude11:04:05

Not sure what the transport stuff is about. Do you have an example?

Benjamin13:04:39

nrepl.transport

(defprotocol Transport
  "Defines the interface for a wire protocol implementation for use
   with nREPL."
  (recv [this] [this timeout]
    "Reads and returns the next message received.  Will block.
     Should return nil the a message is not available after `timeout`
     ms or if the underlying channel has been closed.")
  (send [this msg] "Sends msg. Implementations should return the transport."))
A transport object is added to the message context that is passed to the middleware handler. In principle a middleware can call recv and as far as I understand wait for a message. In practice this is mostly used to wrap a transformation for a handler. (Basically a map or filter in our scheme). The idiom in middleware code seems to be to implement Transport and modifying the send while leaving recv alone - I have not found any example for recv. Here is a representative example of imeplementing the protocol:
(defn- caught-transport
  [{:keys [transport] :as msg} opts]
  (reify Transport
    (recv [_this]
      (transport/recv transport))
    (recv [_this timeout]
      (transport/recv transport timeout))
    (send [this {:keys [::throwable] :as resp}]
      (let [{:keys [::caught-fn ::print?]} (-> (merge msg (bound-configuration) resp opts)
                                               (select-keys configuration-keys))]
        (when throwable
          (caught-fn throwable))
        (transport/send transport (cond-> (apply dissoc resp configuration-keys)
                                    (and throwable print?)
                                    (update ::print/keys (fnil conj []) ::throwable)
                                    (not print?)
                                    (dissoc ::throwable))))
      this)))
cider-nrepl uses transport/send to communicate with the client. with-safe-transport . Is calling send with the result of a handler fn.

borkdude15:04:35

Thanks, this seems another incompatibility with the xform approach, or maybe not inherently?

Benjamin15:04:55

Yes, our approach has the paradigm of response by incoorparting responses into the transformation; While nrepl gives the power to respond and recieve ad-lib.

Benjamin15:04:43

(which is indeed way more messy)