nrepl

ericdallo 2024-04-13T18:20:41.875029Z

I'm fixing a bug in http://github.com/afucher/clojure-repl-intellij (using cider-nrepl) where when user runs a test via test op that prints something to stdout, the out is not printed, checking the nrepl response there is nothing indeed in the return including the out any clues?

ericdallo 2024-04-13T18:23:10.528479Z

I debugged cider via nrepl-log-messages and it's curious the when running the test, the out comes from a previous already responded load-file message, even after a response with done status, why that happens? code:

(ns clojure-sample.core-test
  (:require
   [clojure.test :refer [deftest is]]))

(deftest b-test
  (println "foo")
  (is (= {:a 2 :b 2}
         {:a 2 :b 2})))
nrepl log:
(-->
  id         "1"
  op         "clone"
  time-stamp "2024-04-13 15:22:10.283721855"
)
(<--
  id          "1"
  session     "932971b8-9799-4b75-853c-ad1c35f8a716"
  time-stamp  "2024-04-13 15:22:10.297377285"
  new-session "0d15a061-eab5-4763-9c44-5c4e21aa8209"
  status      ("done")
)
(-->
  id         "2"
  op         "clone"
  time-stamp "2024-04-13 15:22:10.315897681"
)
(<--
  id          "2"
  session     "498400b5-6231-4362-8b6f-c7663e49cb10"
  time-stamp  "2024-04-13 15:22:10.317968017"
  new-session "ad06e15c-17ae-4db5-ae47-d6690282b57f"
  status      ("done")
)
(-->
  id         "3"
  op         "describe"
  session    "0d15a061-eab5-4763-9c44-5c4e21aa8209"
  time-stamp "2024-04-13 15:22:10.336770703"
)
(<--
  id         "3"
  session    "0d15a061-eab5-4763-9c44-5c4e21aa8209"
  time-stamp "2024-04-13 15:22:10.346064256"
  aux        (dict ...)
  ops        (dict ...)
  status     ("done")
  versions   (dict ...)
)
(-->
  id                                 "4"
  op                                 "eval"
  session                            "0d15a061-eab5-4763-9c44-5c4e21aa8209"
  time-stamp                         "2024-04-13 15:22:10.361982523"
  code                               "(when-let [requires (resolve 'clojure.main/repl-requires)]
 ..."
  column                             1
  file                               "*cider-repl dev/clojure-sample:localhost:37107(clj)*"
  inhibit-cider-middleware           "true"
  line                               11
  nrepl.middleware.print/buffer-size 4096
  nrepl.middleware.print/options     (dict ...)
  nrepl.middleware.print/print       "cider.nrepl.pprint/pprint"
  nrepl.middleware.print/quota       1048576
  nrepl.middleware.print/stream?     "1"
)
(<--
  id         "4"
  session    "0d15a061-eab5-4763-9c44-5c4e21aa8209"
  time-stamp "2024-04-13 15:22:10.413409347"
  value      "nil"
)
(<--
  id         "4"
  session    "0d15a061-eab5-4763-9c44-5c4e21aa8209"
  time-stamp "2024-04-13 15:22:10.451356675"
  ns         "user"
)
(<--
  id         "4"
  session    "0d15a061-eab5-4763-9c44-5c4e21aa8209"
  time-stamp "2024-04-13 15:22:10.451676630"
  status     ("done")
)
(-->
  id         "5"
  op         "out-subscribe"
  session    "0d15a061-eab5-4763-9c44-5c4e21aa8209"
  time-stamp "2024-04-13 15:22:10.452433042"
)
(-->
  id                                 "6"
  op                                 "init-debugger"
  session                            "0d15a061-eab5-4763-9c44-5c4e21aa8209"
  time-stamp                         "2024-04-13 15:22:10.453057500"
  nrepl.middleware.print/buffer-size 4096
  nrepl.middleware.print/options     (dict ...)
  nrepl.middleware.print/print       "cider.nrepl.pprint/pprint"
  nrepl.middleware.print/quota       1048576
  nrepl.middleware.print/stream?     "1"
)
(-->
  id                           "7"
  op                           "version"
  session                      "0d15a061-eab5-4763-9c44-5c4e21aa8209"
  time-stamp                   "2024-04-13 15:22:10.459719031"
  debug                        "false"
  insert-newline-after-require "true"
  prefix-rewriting             "false"
)
(<--
  id         "7"
  session    "0d15a061-eab5-4763-9c44-5c4e21aa8209"
  time-stamp "2024-04-13 15:22:10.501436776"
  status     ("done")
  version    "3.9.1"
)
(-->
  id                           "8"
  op                           "version"
  session                      "0d15a061-eab5-4763-9c44-5c4e21aa8209"
  time-stamp                   "2024-04-13 15:22:10.523255250"
  debug                        "false"
  insert-newline-after-require "true"
  prefix-rewriting             "false"
)
(<--
  id         "8"
  session    "0d15a061-eab5-4763-9c44-5c4e21aa8209"
  time-stamp "2024-04-13 15:22:10.525411810"
  status     ("done")
  version    "3.9.1"
)
(-->
  id                           "9"
  op                           "artifact-list"
  session                      "0d15a061-eab5-4763-9c44-5c4e21aa8209"
  time-stamp                   "2024-04-13 15:22:10.547925544"
  debug                        "false"
  force                        "false"
  insert-newline-after-require "true"
  prefix-rewriting             "false"
)
(<--
  id            "5"
  session       "0d15a061-eab5-4763-9c44-5c4e21aa8209"
  time-stamp    "2024-04-13 15:22:10.620449309"
  out-subscribe "0d15a061-eab5-4763-9c44-5c4e21aa8209"
  status        ("done")
)
(<--
  id         "9"
  session    "0d15a061-eab5-4763-9c44-5c4e21aa8209"
  time-stamp "2024-04-13 15:22:11.565591701"
  artifacts  ("side-fx" ...)
  status     ("done")
)
(-->
  id         "10"
  op         "classpath"
  session    "0d15a061-eab5-4763-9c44-5c4e21aa8209"
  time-stamp "2024-04-13 15:22:13.737886934"
)
(<--
  id         "10"
  session    "0d15a061-eab5-4763-9c44-5c4e21aa8209"
  time-stamp "2024-04-13 15:22:13.746349344"
  classpath  ("/home/greg/dev/clojure-sample/test" ...)
  status     ("done")
)
(-->
  id              "11"
  op              "ns-list"
  session         "0d15a061-eab5-4763-9c44-5c4e21aa8209"
  time-stamp      "2024-04-13 15:22:13.759055185"
  exclude-regexps ("^cider.nrepl" "^refactor-nrepl" "^nrepl")
)
(<--
  id         "11"
  session    "0d15a061-eab5-4763-9c44-5c4e21aa8209"
  time-stamp "2024-04-13 15:22:13.830341114"
  ns-list    ("arrangement.core" ...)
  status     ("done")
)
(-->
  id         "12"
  op         "load-file"
  session    "0d15a061-eab5-4763-9c44-5c4e21aa8209"
  time-stamp "2024-04-13 15:22:18.239923435"
  file       "(ns clojure-sample.core-test
  (:require
   [clojure.test :r..."
  file-name  "core_test.clj"
  file-path  "/home/greg/dev/clojure-sample/test/clojure_sample/core_test...."
)
(<--
  id         "12"
  session    "0d15a061-eab5-4763-9c44-5c4e21aa8209"
  time-stamp "2024-04-13 15:22:18.647142630"
  value      "#'clojure-sample.core-test/b-test"
)
(<--
  id         "12"
  session    "0d15a061-eab5-4763-9c44-5c4e21aa8209"
  time-stamp "2024-04-13 15:22:18.656653776"
  status     ("done")
)
(<--
  id                 "12"
  session            "0d15a061-eab5-4763-9c44-5c4e21aa8209"
  time-stamp         "2024-04-13 15:22:19.049390562"
  changed-namespaces (dict ...)
  repl-type          "clj"
  status             ("state")
)
(-->
  id         "13"
  op         "info"
  session    "0d15a061-eab5-4763-9c44-5c4e21aa8209"
  time-stamp "2024-04-13 15:22:22.975291769"
  context    "nil"
  ns         #("clojure-sample.core-test" 0 24 (face lsp-face-semhl-namespace ws-butler-chg chg help-echo cider--help-echo fontified t))
  sym        "clojure-sample.core-test/b-test"
)
(<--
  id         "13"
  session    "0d15a061-eab5-4763-9c44-5c4e21aa8209"
  time-stamp "2024-04-13 15:22:23.399986150"
  column     1
  file       "file:/home/greg/dev/clojure-sample/test/clojure_sample/core_..."
  line       5
  name       "b-test"
  ns         "clojure-sample.core-test"
  status     ("done")
)
(-->
  id         "14"
  op         "test"
  session    "0d15a061-eab5-4763-9c44-5c4e21aa8209"
  time-stamp "2024-04-13 15:22:23.418434169"
  fail-fast  "true"
  load?      "true"
  ns         #("clojure-sample.core-test" 0 24 (face lsp-face-semhl-namespace ws-butler-chg chg help-echo cider--help-echo fontified t))
  tests      ("b-test")
)
(<--
  id         "12"
  session    "0d15a061-eab5-4763-9c44-5c4e21aa8209"
  time-stamp "2024-04-13 15:22:23.525720730"
  out        "foo
"
)
(<--
  id               "14"
  session          "0d15a061-eab5-4763-9c44-5c4e21aa8209"
  time-stamp       "2024-04-13 15:22:23.570855530"
  elapsed-time     (dict ...)
  gen-input        nil
  ns-elapsed-time  (dict ...)
  results          (dict ...)
  summary          (dict ...)
  testing-ns       "clojure-sample.core-test"
  var-elapsed-time (dict ...)
)
(-->
  id         "15"
  op         "info"
  session    "0d15a061-eab5-4763-9c44-5c4e21aa8209"
  time-stamp "2024-04-13 15:22:23.571408061"
  context    "nil"
  ns         "user"
  sym        "clojure-sample.core-test/b-test"
)
(<--
  id         "14"
  session    "0d15a061-eab5-4763-9c44-5c4e21aa8209"
  time-stamp "2024-04-13 15:22:23.573468596"
  status     ("done")
)
(<--
  id         "15"
  session    "0d15a061-eab5-4763-9c44-5c4e21aa8209"
  time-stamp "2024-04-13 15:22:23.573642817"
  column     1
  file       "file:/home/greg/dev/clojure-sample/test/clojure_sample/core_..."
  line       5
  name       "b-test"
  ns         "clojure-sample.core-test"
  status     ("done")
)
Repro: • starts repl • load-file • run test at point

ericdallo 2024-04-13T18:26:47.458029Z

In this case, when running the test op, I see a response of id 12 with the foo out, even if load-file was already responded before with done status, I thought reading the protocol that could not happen since the done status indicates the end of that op responses

2024-04-13T21:40:02.775919Z

have you tried https://github.com/jpmonettas/nrepl-flowstorm-debug ?

2024-04-13T23:07:19.364069Z

I just looked into it and what I see comparing the execution of a normal interruptible-eval op vs the test op is that the first one binds to *out* a custom PrintWriter closed over the msg related to the op as you can see in the image

2024-04-13T23:08:33.391639Z

so whatever does a println ends up in that PrintWriter, which uses the msg it is closed over to send the print back. So sending the print result with the correct id

2024-04-13T23:09:20.786519Z

now the test op doesn't bind *out* to anything and just uses whatever is on the session as you can see in the picture

2024-04-13T23:09:59.833189Z

that PrintWriter is bound to a different msg (probably the root binding of nrepl.middleware.interruptible-eval/*msg*

2024-04-13T23:15:02.607569Z

so when the test run and the println executes you end in a situation like you see on the picture

2024-04-13T23:15:54.956149Z

with the PrintWriter being executed is a PrintWriter bound to a different message that the one the test op started

ericdallo 2024-04-13T23:28:01.373649Z

I knew about but never tried flowstorm-debug, but wow, thank you for the detailed explanation @jpmonettas! So I suppose that was not intentional for the test op? If not, any suggestions on how to avoid that?

2024-04-13T23:37:00.606289Z

so, I just hacked this on cider-nrepl

2024-04-13T23:37:20.161029Z

and now it works fine

2024-04-13T23:37:27.154609Z

2024-04-13T23:38:23.349969Z

the test op msg is id 14 and the foo4242 I'm printing comes back in the response of id 14

2024-04-13T23:39:09.207839Z

but I don't know, probably :err also needs to be set there

2024-04-13T23:40:01.917589Z

maybe @vemv knows a better way to fix this since it is a cider-nrepl thing

vemv 2024-04-14T08:48:30.272489Z

Is cider.nrepl.middleware.out part of your cider-nrepl stack? (it's there by default) Things may start working by adding it (or removing it, idk 😂) if this persists we'd be happy to attend the issue over GH - I don't have much bandwidth these weeks

2024-04-14T11:50:15.867259Z

by looking at the code cider.nrepl.middleware.out seems to provide out-subscribe and out-unsubscribe which are to change clojure.core/*out* to print stuff running outside of eval in the active session, but will not make what is printed by the test op to come back in the response to that same op

2024-04-14T12:08:16.593239Z

I'm not sure if we should treat this as a bug on cider-nrepl or not, it kind of breaks users expectation. But for your situation @ericdallo I think you can do the same thing that cider is doing, which is instead of handling out on each op response (like test) you handle out globally like this : • after you connect to the nrepl server https://github.com/clojure-emacs/cider/blob/master/cider-connection.el#L380-L385 • which will just call to that out-subscribe op and https://github.com/clojure-emacs/cider/blob/master/cider-connection.el#L297-L300 to print whatever comes on the session out on your intelliJ window

ericdallo 2024-04-14T12:35:53.068539Z

From a user perspective I'd expect test to be pretty similar to eval in that term, I think would be nice to support that on cider-nrepl side. @jpmonettas thanks! that makes sense, I knew I probably needed a way to subscribe to messages but I couldn't find easily how to do it with nrepl.core lib, but with those pointers I may manage to make it work, will try, thank you again for the help!

1
ericdallo 2024-04-14T13:12:18.585349Z

I just https://github.com/afucher/clojure-repl-intellij/pull/63/commits/c64b1e1af5e9c17974bcf92dfc672efbab4394a1 the out-subscribe , but I'm not understanding how this "callback" works via nrepl.core/message communication in clj, I'm probably misunderstanding the communication client <-> server because ATM I just send sync messages and wait for return https://github.com/afucher/clojure-repl-intellij/blob/fix-print-tests/src/main/clojure/com/github/clojure_repl/intellij/nrepl.clj#L25, so I don't see a option to subscribe or add a fn you know, also the cider-docs https://docs.cider.mx/cider-nrepl/nrepl-api/ops.html#out-subscribe about it or I am missing something really obvious

ericdallo 2024-04-14T13:14:39.539389Z

Ah, https://docs.cider.mx/cider-nrepl/nrepl-api/supplied_middleware.html to use the wrap-out midddleware for that to work? maybe that's the callback i'm searching

2024-04-14T13:16:10.693059Z

I'm not an expert in any of this but wrap-out middleware should be loaded with the standard cider middleware https://github.com/clojure-emacs/cider-nrepl/blob/31a3d02e13ae1daff0637330c27d83f5943a8486/src/cider/nrepl/middleware.clj#L22

ericdallo 2024-04-14T13:17:26.350499Z

yeah, I'm trying this now, I think I never needed any other middleware until now, so I'll have to support that 😅

2024-04-14T13:18:21.557029Z

so all those should be already loaded for you if your nrepl server is starting with the cider middleware

ericdallo 2024-04-14T13:19:11.882619Z

hum, so you are saying I don't need to send a add-middleware op?

2024-04-14T13:19:30.892099Z

> but I'm not understanding how this "callback" works via I think the callback is a emacs cider thing that will install a nrepl response handler to check the :out key of any message and print it on the buffer

2024-04-14T13:19:56.077199Z

> hum, so you are saying I don't need to send a add-middleware op? how are you starting the nrepl server?

ericdallo 2024-04-14T13:21:15.579099Z

I start with a pretty similar command that cider does using https://github.com/afucher/clojure-repl-intellij/blob/c64b1e1af5e9c17974bcf92dfc672efbab4394a1/src/main/clojure/com/github/clojure_repl/intellij/repl_command.clj#L37, but in the end it turns out to result in something like:

lein update-in :dependencies conj [nrepl/nrepl "1.0.0"] -- update-in :plugins conj [cider/cider-nrepl "0.45.0"] -- repl :headless :host localhost

2024-04-14T13:23:27.830219Z

so I think what cider is doing is to just have a function that process all responses, and if it sees a :out in any of them prints it on the repl

ericdallo 2024-04-14T13:23:34.079319Z

ok, so I think the problem is that all nrepl communication is done sync, sending message and waiting for the response via nrepl.core/message, I feel like there must be some way to "listen" to the nrepl server too

2024-04-14T13:24:02.748239Z

yeah, so nrepl is request->multi response protocol

ericdallo 2024-04-14T13:24:50.558799Z

yeah and since I'm using nrepl.core/combine-responses https://github.com/afucher/clojure-repl-intellij/blob/c64b1e1af5e9c17974bcf92dfc672efbab4394a1/src/main/clojure/com/github/clojure_repl/intellij/nrepl.clj#L27, we wait until we receive a done status, but then cider doesn't follow that standard and send a out for a previous load-file that the done was already sent

2024-04-14T13:25:23.425629Z

yeah

2024-04-14T13:26:47.877939Z

looks like it is doing there like a "server sent events" thing, with a request that is made but never done, so you can send messages back forever, so whenever something prints you can send it back to the client

ericdallo 2024-04-14T13:27:13.898809Z

exactly

ericdallo 2024-04-14T13:28:06.329219Z

so maybe I should change how https://github.com/afucher/clojure-repl-intellij/blob/c64b1e1af5e9c17974bcf92dfc672efbab4394a1/src/main/clojure/com/github/clojure_repl/intellij/nrepl.clj#L19-L27, the server communication to instead of being sync, listen somehow to every response message the server sends

2024-04-14T13:29:02.736599Z

I guess what you can do is to add a general response message processor (not a combined one) so you don't depend on status done, and in that gral processor you handle :out and :err

ericdallo 2024-04-14T13:29:25.726309Z

yeah, good suggestion

2024-04-14T13:30:00.192799Z

iiuc is what cider is doing

ericdallo 2024-04-14T13:30:28.921769Z

the problem is that would work if I have a way to handle messages async, which I don't see how to do that with nrepl.core lib right now

ericdallo 2024-04-14T13:31:48.782199Z

maybe I should use nrepl.core/client-session and not only message

2024-04-14T13:32:09.251919Z

that is the global thing cider is using

2024-04-14T13:32:19.638399Z

and it provides a handler for out, and another one for err

ericdallo 2024-04-14T13:32:37.473519Z

yeah, I was just seeking a way to do that in Clojure

2024-04-14T13:32:52.806449Z

> the problem is that would work if I have a way to handle messages async, which I don't see how to do that with nrepl.core lib right now long time since I have worked with that, let me see

2024-04-14T13:40:54.976789Z

it looks like the nrepl.core/message (the one who waits until status done to return) is using nrepl.core/response-seq under the hood, which will give you a infinite sequence of responses for a transport

ericdallo 2024-04-14T13:45:07.312109Z

but when I use it it returns a finite seq of responses, I can't see how to use it and "listen" besides waiting sync for that response

2024-04-14T13:45:49.007829Z

yeah, but message is what makes it sync

2024-04-14T13:46:13.108869Z

because message will send, and wait for something with :status done under the same sent message id

ericdallo 2024-04-14T13:46:58.920329Z

I see, so I'd need to use delimited-transport-seq manually?

ericdallo 2024-04-14T13:47:22.904109Z

I think that's where nrepl.core/client-session enters

2024-04-14T13:47:30.798419Z

or maybe even lower level response-seq

ericdallo 2024-04-14T13:48:02.119679Z

client-session does what message does, but waits for a session-closed which seems to be fine

2024-04-14T13:48:37.726019Z

oh yeah, that could be easier

ericdallo 2024-04-14T13:49:33.693789Z

I just can't make it work 😅 I don't see a example of it too anywhere

2024-04-14T14:05:01.605649Z

I'm not sure either, but maybe around these lines :

clj -Sdeps '{:deps {nrepl/nrepl {:mvn/version "1.0.0"}}}'                                                            
Clojure 1.11.1                                                                                                            
user=> (require '[nrepl.core :as n])                                                                                      
user=> (def conn (n/connect :port 38859))                                                                                 
user=> (def client (n/client conn Long/MAX_VALUE))                                                                                  
user=> (def send (n/client-session client))                                                                               
user=> (doseq [r (send {:op "eval" :code "(+ 2 3)"})]
         (println r))              

2024-04-14T14:05:56.086569Z

so, when you send a message (like the first one), you get a infinite sequence if you provide a long timeout

2024-04-14T14:06:28.800259Z

all this is as hacky as you get, but I'm trying to figure out if this approach would work for what you want with the official nrepl client

ericdallo 2024-04-14T14:08:22.738189Z

I think that kinda works but I'd need to move that to a future or core.async I guess

2024-04-14T14:12:45.700879Z

yeah, or like :

(future
  (let [responses ((n/client-session client) {:op "out-subscribe"})]
    (doseq [r responses]
      (println "Process session response" r))))

2024-04-14T14:13:23.311119Z

but hmm, this seams super hacky, not sure if this is the way this was originally designed

2024-04-14T14:14:01.424249Z

not sure how VSCode deals with it (if it deals with it at all)

2024-04-14T14:14:49.018069Z

maybe it only works on cider because it has a elisp custom nrepl client?

ericdallo 2024-04-14T14:16:24.851359Z

I don't think so, I can't find a nrepl-client integration example in Clojure (which is weird), but Calva does with TS and other clients with other langs

ericdallo 2024-04-14T14:16:31.414649Z

https://nrepl.org/nrepl/usage/clients.html

2024-04-14T14:18:10.393639Z

because cider has this https://github.com/clojure-emacs/cider/blob/master/nrepl-client.el#L829-L855 in its own nrepl-client implementation

2024-04-14T14:18:26.078959Z

so it can handle things like that

ericdallo 2024-04-14T14:19:14.975639Z

so maybe cider is only manually handling the socket communication or so

2024-04-14T14:20:29.847879Z

yeah, so cider includes its own version of nrepl client, written in elisp, which has functionality for defining a handler for every response

2024-04-14T14:20:55.183379Z

it can't use any of jvm nrepl client code

ericdallo 2024-04-14T14:21:46.394769Z

yeah I know, but it should be a way of doing similar in clojure with current nrepl.core or cider-nrepl library right?

ericdallo 2024-04-14T14:21:56.377979Z

maybe @vemv knows

2024-04-14T14:23:37.864779Z

maybe there is, but it is a pretty weird case, since I think this is the only weird case that would need something like this, unless you want to implement SSE over nrepl

ericdallo 2024-04-14T14:24:13.186159Z

exactly, maybe fixing in cider-nrepl would be easier

ericdallo 2024-04-14T14:24:33.785569Z

I just wish I could solve this issue faster as it's a pretty critical issue for the plugin

2024-04-14T14:26:15.433459Z

but if you solve it for the test op in cider-nrepl, it will still be missing other printlns that happens outside eval or test contexts, something from background running threads isn't? Since cider-nrepl seems to be using this SSE techniques I guess the clients would need to support it

2024-04-14T14:26:59.054889Z

let's see what else is on nrepl codebase

ericdallo 2024-04-14T14:28:41.650209Z

ah, true..

2024-04-14T14:29:21.456659Z

maybe instead of using nrepl/core.clj which looks like a thin wrapper over transport/recv and transport/send, you can just deal with the transport yourself

2024-04-14T14:29:54.647059Z

you can get the transport with (-> client meta :nrepl.core/transport)

2024-04-14T14:30:32.428779Z

and then send and receive single messages with send and recv

2024-04-14T14:38:02.376799Z

and then create a thin wrapper over that infrastructure so you still have your "sync message" which will match messages sent with responses by id, and also something to wait for the status done and combine the responses

ericdallo 2024-04-14T14:39:09.150799Z

yeah, although I was trying to avoid need to handle with that communication, I think that will work and probably be extensible for future changes on that

ericdallo 2024-04-14T14:39:13.083819Z

will try

2024-04-14T14:39:49.554919Z

ok, have to leave for today. Good luck with that!

ericdallo 2024-04-14T14:39:58.868459Z

thank you for the help!

2024-04-14T14:40:06.107399Z

np

ericdallo 2024-04-16T19:24:15.586019Z

Hey @jpmonettas just letting you know that your suggestion worked :) I implemented it https://github.com/afucher/clojure-repl-intellij/pull/67, it's not perfect, but solves the problem, I wish there was a better way/API to have that working out of the box from nrepl.core

2024-04-16T19:30:00.582839Z

oh nice! Yeah, I guess that capability of listening to messages independently of their id like you did needs to be added to nrepl.core. But on the other side I'm not sure if this is a deficiency of nrepl or cider-nrepl is abusing the protocol? Maybe proper SSE needs to be added to nrepl instead?

ericdallo 2024-04-16T19:30:51.076789Z

yeah, I feel like SSE would be a nice addition as it's exactly what cider-nrepl is trying to do

ericdallo 2024-04-16T19:31:09.325939Z

c/c @vemv ☝️

ericdallo 2024-04-16T19:31:23.029569Z

Anyway, thank you for the help debugging that @jpmonettas!

2024-04-16T19:31:55.889679Z

you are welcome! happy to hear you unblocked your clojure-repl-intellij plugin!

🎉 1
vemv 2024-04-16T22:08:51.647319Z

I didn't / don't quite have the bandwith to go over this discussion but we'd be happy to receive a summary of the issue over gh

2024-04-16T22:20:14.382519Z

I can make a quick summary. The thing is that cider-nrepl has this ability to send from the server back to the client "printlns" that don't correspond to any specific request message, so kind of Server Sent Events over nrepl. This works for Cider because the elisp nrepl client listens to any response packet with a :out and adds it to the buffer, so it can render printlns not related to any message it sent. Now if you want to support this from a client using the official nrepl client you can't easily, because it only provides a way of reading responses for the messages you sent. So the question here are : is nrepl lacking client support for this ? or is cider-nrepl "abusing" the protocol in a hacky way? Should nrepl support SSE? or are we missing something? I hope it makes sense

1
vemv 2024-04-16T22:25:32.830229Z

I don't know. Feel free to go over #nrepl or a nrepl issue report - I'm quite sure Bozhidar would enjoy pondering on these :)

2024-04-16T22:26:00.959629Z

sure, I can add it

2024-04-16T22:37:10.623359Z

https://github.com/nrepl/nrepl/issues/315 created this, I hope I made a good job explaining it

vemv 2024-04-16T22:39:08.361379Z

From intuition I'd say that it's normal nrepl design that a given request can have N async responses. I don't think elisp is listening to 'anything' - instead it's seeing async responses for past requests I subscribed out of curiosity

2024-04-16T22:42:52.626689Z

the thing is that withott SSE support when you send something back you need to send it as a response to some message id, which is kind of hacky, unless you use one message as the message that starts the SSE chanel, which could be fine I guess. In that case nrepl client should provide something to consume this.

ericdallo 2024-04-16T22:49:08.529209Z

yep, it's weird to see coming from server:

{:id 123 :op "load-file"  :status #{"done"}}
;; after some time when running other ops
{:id 123 :out "foo"}
so it's not really done the 123

vemv 2024-04-16T22:54:46.708619Z

Yeah that's usual. eval, load-file, etc all can create e.g. a (future (while true (println))) So the op is done, but we cannot know if/when output is done (IIRC that's the very reason why have this client issue https://github.com/clojure-emacs/cider/issues/3206)