I realized tonight that it would be really easy to create a Socket REPL adapter that automatically submits forms/values to Cognitect's REBL, without needing the customization I've previously been adding to Chlorine: https://github.com/seancorfield/socket-rebl -- this would also be usable by Clover to integrate with REBL, without needing custom code.
Ah, I've just realized why this won't actually work! Chlorine starts up a separate Socket REPL over which it sends the actual evaluations 😞
I suspect Clover does the same? Oh well, it's still a nice, useful utility for folks who want to telnet into a REBL instance with a Socket REPL I suppose 😞
Almost - Chlorine sends a piece of code that will make the REPL more programmable. Without it, it would be really difficult to add tooling over the REPL.
But... maybe we can somehow work on this direction? Maybe make this "socket REBL" return the form that Chlorine expects? I'll investigate alternatives 😄
(after all, there's currently support for at least 4 different REPLS: the "regular socket REPL", "Clojure with UNREPL", "nREPL", and "Shadow-CLJS Relay REPL")
@mauricio.szabo The only difference between the bare bones Socket REPL and my library above, is the :eval
function is wrapped to call cognitect.rebl/submit
on the form and value: https://github.com/seancorfield/socket-rebl/blob/master/src/socket/rebl.clj#L13-L21
What's interesting is that this causes REBL to show the negotiation that Chlorine does, since it adds all those initial forms to REBL as they are evaluated. But once Chlorine has negotiated that this is a regular Socket REPL on the JVM, I gather that starts a second socket REPL for the unrepl stuff to communicate over?
Here's what I see in REBL, sent by Chlorine, before it switches over to a separate socket REPL:
(it's in reverse time order: most recent command at the top)
Yes, there are two REPLs connected: one for autocomplete, load-file, goto-var-definition, etc, and another for evaluations so using one doesn't interfere on other 🙂
It sure would be nice if they were swapped around so evaluations happened on the primary REPL and all the other stuff happened on the secondary.
(since the primary REPL is the one users have control over)
I didn't dig too deep into non-eval ops to see if anything else uses the primary REPL. Will do that when I get off my daily standup.
(I believe that's the way it is - the first REPL to be connected is the "primary" 😄)
OK, I tested, and it doesn't look like anything goes over the primary socket REPL after the negotiation code.
I verified that connecting to that Socket REPL from other sources (e.g., telnet) does indeed go through that submit-eval
above, so socket.rebl/repl
is used as the :accept
for new connections, but none of Chlorine's built-in operations go through it, so all of the operations must be happening on secondary socket REPLs that are opened after negotiation @mauricio.szabo FYI
No, I believe I know what happens...
As Chlorine is using UNREPL, it is probably starting a new REPL inside the Socket REPL - by running clojure.main/repl
or something, so when it issues this command, it never returns then newer commands never go through...
Ah, yes, that's exactly what happens: https://github.com/mauricioszabo/unrepl/blob/master/src/unrepl/repl.clj#L410
Ah, yes, that would do it too 🙂
So unrepl would essentially need an :eval
middleware wrapper in order to make my socket.rebl
stuff work. Oh well...
Some experiments: by using some new features of interactive-renderer, I'm trying to change the way test errors are being rendered on the editor: