Fork me on GitHub
#nrepl
<
2021-05-17
>
daslu20:05:01

Hi! @sakalli and I are creating a small middleware that listens to evaluation of code and keeps track of evaluation results. (This is part of an upcoming version of the Notespace project.) With :op "eval", this seems to work nicely. However, we are also interested in :op "load-file", since that is the kind of request when one evaluates a whole buffer in CIDER. Then, the nREPL response only tells about the evaluation result of the last top-level form. This kind of op directly calls clojure.lang.Compiler/load: https://github.com/clojure/tools.nrepl/blob/2263b6b/src/main/clojure/clojure/tools/nrepl/middleware/load_file.clj#L62 So, it seems that on whole-buffer evaluation, we will not be able to get the return values of intermediate top-level forms, but only of the last one. Any ideas about how to overcome that?

bozhidar20:05:17

There's no way to circumvent this with load-file.

bozhidar20:05:16

If you need to eval all top-level forms you'll need to walk over them and run eval for each. That won't be a problem if you eval in a single session as the evaluations will be serialized.

daslu20:05:31

Thanks for the quick help, @bozhidar! We tried to evaluate a region with a few top-level forms (through :op "eval"), and it actually sent us multiple responses with all evaluation values. Is it surprising? Request (removed the bit :session member, so that it prints nicely):

{:transport
 #object[nrepl.middleware.caught$caught_transport$reify__915 0x5e5191a5 "[email protected]"],
 :ns "notespace.nrepl",
 :nrepl.middleware.print/print-fn
 #function[nrepl.middleware.print/wrap-print/fn--891/print--893],
 :file "/home/daslu/dev/scicloj/notespace/src/notespace/nrepl.clj",
 :load-tests? "true",
 :nrepl.middleware.print/quota 1048576,
 :nrepl.middleware.print/print "cider.nrepl.pprint/pr",
 :op "eval",
 :column 1,
 :line 50,
 :nrepl.middleware.caught/caught-fn
 #function[clojure.main/repl-caught],
 :id "132",
 :code "(+ 1 2)\n\n(+ 3 4)\n\n",
 :nrepl.middleware.print/stream? []}
Response messages:
{:id "132",
 :session "736cc68a-a5fe-44d5-8906-0ba56ca15dda",
 :ns "notespace.nrepl",
 :value 3,
 :nrepl.middleware.print/keys #{:value}}

{:id "132",
 :session "736cc68a-a5fe-44d5-8906-0ba56ca15dda",
 :ns "notespace.nrepl",
 :value 7,
 :nrepl.middleware.print/keys #{:value}}

{:id "132",
 :session "736cc68a-a5fe-44d5-8906-0ba56ca15dda",
 :status #{:done}}

daslu20:05:01

If it seems interesting, I can share a self-contained example tomorrow. Anyway, your comment already helped wonderfully. 🙏

dpsutton20:05:51

that is expected to me. evaluating a region can (and here does) have multiple effects

dpsutton20:05:01

load-file is a primitive offered by the clojure compiler

pez21:05:45

I don’t understand the answer…

pez21:05:42

Also, eval a region and get back results for each top level form in it surprises me. I would expect the reader to get the text, eval each form and give me back the result of the last thing evaled.

dpsutton21:05:23

that's just not what (def x 1)(def y 2) (def z 3) would ever do, and that's all evaling a region does, just send a region over to the repl

dpsutton21:05:05

/tmp ❯❯❯ clj
Clojure 1.10.3
user=> (def x 1)(def y 2)(def z 3)
#'user/x
#'user/y
#'user/z
user=>

pez21:05:19

I’m now realizing that Calva does not have a working eval region command.

dpsutton21:05:35

it's probably quite infrequently used. i'd wait for a feature request to be honest

pez21:05:34

Well, the command is actually named Evaluate current form (or selection) so we are breaking the promise…

pez21:05:20

Noone has complained so far, and it must have been broken for quite a while. So you are probably right about infrequent.