> I understand the concern but after some earlier iterations I came to the conclusion that the input stream must be left untouched. @cgrand could you say a bit more about why you came to this conclusion?
I considered two approaches: full framing (eg {:id id :code "code"}
and interspersed “metadata” (adding stuff between forms).
interspersed metadata require the client to perfectly parse user input which is a strong requirement (and makes it brittle towards language change).
framing makes further upgrades difficult (transitioning from framed to streamed and (potentially) framed again) especially when some further input is already buffered. furthermore framing encourages to multiplex usages of a single connection, which adds complexity to the server. Plus in no time you are reinventing nrepl-sans-bencode 🙂
I've made that comment. EDN over socket as a new transport for nrepl could bring some of the benefits on unrepl.
But nrepl is fairly tied to bencode, and everything is tied to the limitations of the 4 data types that are there.
thanks @cgrand, that makes sense
really?
yeah, I think those are reasonable arguments.
the problem still exists somewhat from what I can tell though, right?
as a curious idea, could unrepl provide a form that you can put code into? & that would essentially be (unrepl/with-id)
?
e.g. (unrepl/with-id 1 (+ 1 1))
well
In unravel I just send [my-eval-id (form-to-eval)]
low-tech solution to track replies
*1
? exceptions etc?
Is offset management that hard? (is my proposed solution too cumbersome?)
I feel I'm missing the context
@pesterhazy it may be something you have missed
now unrepl sends :echo
messages right after read but before eval
these messages contains the offset (from the start of the unrepl session) and length of the form being evaluated
offset being the number of evals executed so far?
number of input characters
ah no chars
UTF-16 code units with normalized newlines to be precise 🙂
(aka don’t send CRLF)
that's for when I send (+ 1 2) (+ 3 4)
, that is, I'll get multiple :echo
s?
I think that's a useful feature
> (+ 1 2)(map inc (range 5))(str "hello" " " "world")
< [:echo {:from [1 1], :to [1 8], :offset 0, :len 7} 1]
< [:started-eval {:actions {:interrupt (unrepl.repl/interrupt! :session335 1), :background (unrepl.repl/background! :session335 1)}} 1]
< [:eval 3 1]
< [:echo {:from [1 8], :to [1 27], :offset 7, :len 19} 2]
< [:started-eval {:actions {:interrupt (unrepl.repl/interrupt! :session335 2), :background (unrepl.repl/background! :session335 2)}} 2]
< [:eval (1 2 3 4 5) 2]
< [:echo {:from [1 27], :to [2 1], :offset 26, :len 26} 3]
< [:started-eval {:actions {:interrupt (unrepl.repl/interrupt! :session335 3), :background (unrepl.repl/background! :session335 3)}} 3]
< [:eval "hello world" 3]
[:prompt {:file "unrepl-session", :line 2, clojure.core/*warn-on-reflection* false, clojure.core/*ns* <#C4C63FWP5|unrepl>/ns user}]
seems great for showing exactly where an error is
in the terminal I could show a little arrow e.g.
My problem was a different one. I was to correlate doc
replies, i.e. I want to send something like (send-to-tooling-cx '(doc clojure.core/filter) {:callback show-result})
for that, I need to keep track of evaluations, But using a simple vector with an eval-id works well
Am I right in assuming that :echo
wouldn't help for this case?
I think you are wrong in this case
I mean I get an echo number back
but then I would still have to correlate the echo
response with what I sent
and in pathological cases, I might get an echo
late, or not at all
when you send (doc cojure.core/filter)
you know the offset in your outgoing tooling stream, so when you get the echo you can obtain the eval id
how do I know the offset? I just count how man bytes I've sent so far?
:echo
occurs after read and before eval
couting chars would be better but yes
Oh, didn't realise echo gave back id. I thought it had, I was confused this came up again. Yeah, only "issue" is multiplexing.
which is a non-feature
so there’s no pathological case I think (I’d rather be proven wrong now than in 6 months)
hm I still prefer my simple-minded solution - it only requires me to keep track of one correlation, not two
anyway there's no downsides to allowing both approaches, right?
I’m not going to prevent you from evaluating what you want
I appreciate it 🙂
🙂
send-to-tooling-cx
is local only or not yet written?
it was pseudo-code. The actual function is called call-remote
: https://github.com/pesterhazy/unravel/blob/master/src/unravel/loop.cljs#L155 @cgrand
Thanks
@pesterhazy did you consider processing messages in a slightly different way? Currently you dispatch on connection+tag first. I would dispatch on the group-id first.
sorry, I don't follow. What would the group-id be?
the third component of a message (the eval id if you wish)
ah
what would I do with the group-id?
I’m thinking about the tooling connection
I mean that would be part of using :echo
I guess - keeping associations of group-ids and callbacks
and outbound messages and group-ids
Hmm trying to sort out my ideas...
Let forget the dispatch order for now.
But about :echo
: make send!
takes a callback, the callback is called when :echo
is received, and it sets the real callback in your callbacks
atom.
my concern about dispatch order is that this “real” callback may be stateful (or have an explicit passed (reduce-style) state) and used to process all the messages (`:eval`, :out
etc.) for one form
right that'll work
haven't run into issues with stateful callbacks yet
my plan was to worry about that when I start seeing related issues
do you have a concrete example of such an issue?
It's not much of an issue it's just that I think that it could be useful to process related messages together in stateful functions.
Given how :echo
evolved I'm tempted to rename it :read
When evaluating, is it possible to mark the position in a file that it is? (This might be a general clojure question)
I'm not sure I understand. Do you mean saying "eval this form which was read at line 42 of foo.clj"?
You have to set a couple of dynvars for the file name. Line numbers are metadata to most read forms – but you can't explicitly set them in the source because reading overwrites them.
You understand correctly what I'm asking.
I don't fully understand what you mean about metadata. But I think it's important that they can be set.
https://github.com/clojure/tools.nrepl/blob/master/doc/ops.md#optional-parameters-3 it's possible to do :thinking_face: https://github.com/clojure/tools.nrepl/blob/fcac1e13d6f80eb0db28773247a769c1dc9659b1/src/main/clojure/clojure/tools/nrepl/middleware/interruptible_eval.clj#L48-L53 that's how it's done
So, as a client to unrepl, should I set the line no & column?
See :set-source