Fork me on GitHub
#unrepl
<
2017-08-21
>
rickmoynihan08:08:17

Curious what people here think of: http://langserver.org/ vs the (un)REPL

rickmoynihan08:08:28

for clojure(script) specifically

dominicm08:08:40

There isn't an eval :)

thheller09:08:05

@dominicm but it is trivial to add an eval 😉

thheller09:08:56

@rickmoynihan I had a proof of concept LSP implementation a while back. I’m all for it … just don’t have the time to write/maintain it currently

cgrand09:08:56

Small hack over the weekend: https://github.com/Unrepl/mux

cgrand09:08:39

it’s a naive multiplexer to use when all you have is one pair of streams.

cgrand10:08:16

$ kein
Clojure 1.8.0
user=> (require '[unrepl.mux :refer [mux]])
nil
user=> (mux)
> [:a "(ns usera)\n"]
< [:a "user=> "] ; prompt upon connection
< [:a "nil"] ; value of the ns form
< [:a "\n"]
< [:a "usera=> "]
> [:b "(ns userb)\n"]
< [:b "user=> "]
< [:b "nil"]
< [:b "\n"]
< [:b "userb=> "]
> [:a "(+ 1 1)\n"]
< [:a "2"]
< [:a "\n"]
< [:a "usera=> "]
> [:b "(+ 2 2)\n"]
< [:b "4"]
< [:b "\n"]
< [:b userb=> ]
> [:a nil] ; close :a
> [:a "(+ 1 1)\n"] ; opens a new connection reusing the :a name
< [:a "user=> "]
< [:a "2"]
< [:a "\n"]
< [:a "user=>" ] ; not in usera 

rickmoynihan10:08:02

interesting…

cgrand11:08:05

it’s just the implementation I promised since I gave up on multiplexing input in unrepl proper: use a multiplexing layer below unrepl.

pesterhazy12:08:12

@cgrand, love these little experiments

pesterhazy12:08:48

so :a would be the virtual connection id right?

pesterhazy12:08:40

If I use a new conn-id, mux automatically opens a new session on the same stream?

cgrand12:08:18

yes, it allocates a new connection on the first message (for a given id)

cgrand12:08:45

it closes the connection on receiving nil.

cgrand12:08:53

the id can then be reused

cgrand12:08:28

ids are allocated by the client and it’s not a problem because they are scoped to the current “real” connection

pesterhazy12:08:53

and this doesn't require unrepl necessarily, correct?

pesterhazy13:08:33

I'm assuming so as your example uses a clojure.main/repl

cgrand13:08:00

and you can upgrade any session to what you want (including unrepl)

pesterhazy13:08:12

very nice modular approach

cgrand13:08:18

mux on mux:

pesterhazy13:08:25

does it buffer output? I saw there's a pipe-size

pesterhazy13:08:05

this could be amazing for "inferior process" style tooling

cgrand13:08:17

$kein
Clojure 1.8.0
user=> (require '[unrepl.mux :refer [mux]])
nil
user=> (mux)
[:a "(mux)\n"]
[:a "user=> "]
[:a "[:a \"(inc 41)\n\"]\n"] ; evaluate (inc 41) in the :a session of the muxed :a session
[:a "["]
[:a ":a"]
[:a " "]
[:a "\""]
[:a "u"]
[:a "s"]
[:a "e"]
[:a "r"]
[:a "="]
[:a ">"]
[:a " "]
[:a "\""]
[:a "]"]
[:a "\n"]
[:a "["]
[:a ":a"]
[:a " "]
[:a "\""]
[:a "4"]
[:a "2"]
[:a "\""]
[:a "]"]
[:a "\n"]
[:a "["]
[:a ":a"]
[:a " "]
[:a "\""]
[:a "\\n"]
[:a "\""]
[:a "]"]
[:a "\n"]
[:a "["]
[:a ":a"]
[:a " "]
[:a "\""]
[:a "u"]
[:a "s"]
[:a "e"]
[:a "r"]
[:a "="]
[:a ">"]
[:a " "]
[:a "\""]
[:a "]"]
[:a "\n"]

cgrand13:08:16

output is not buffered (an amount of time-based buffering may be good (see above))

cgrand13:08:24

input is buffered so any input string (length of the read payload, not of the whole message) longer than 16k (default) may block the other sessions

cgrand13:08:00

(or a stalled session accumulating 16k of pending input)

cgrand13:08:34

backpressure could be implemented but I’m not sure it’s worth it

pesterhazy13:08:10

the important thing is the PoC

pesterhazy13:08:58

do you have a network programming background? you seem to know a lot about this

cgrand13:08:12

no, I’m just getting old 😉

pesterhazy13:08:09

so am I but not sure that magically gives me magic powers of protocol implementation 🙂

cgrand14:08:42

watching Alex Miller’s “Deps heaven” talk and realizing that with clj I can ditch my kein script

richiardiandrea14:08:09

yes clj is cool, still in progress though, last time I checked I did not even see instructions in the repo anymore and scripts where only for Mac

cgrand14:08:27

Looking at it, I’m thinking that it needs a flag for easy repl server

pesterhazy15:08:27

I think you should have called it "klein" - "small" in German

pesterhazy15:08:54

that's actually a use case I've heard for unrepl - getting beginners started quickly

cgrand15:08:45

well I called it kein because kein andere JVM was started

cgrand16:08:19

I made a small tweak to mux so that output is buffered at 20Hz: now mux on mux gives:

Clojure 1.8.0
user=> (require ‘[unrepl.mux :refer [mux]])
nil
user=> (mux)
[:a “(mux)\n”]
[:a “user=> “]
[:a “[:a \“(inc 41)\n\“]\n”]
[:a “[:a \“user=> \“]\n”]
[:a “[:a \“42\“]\n”]
[:a “[:a \“\\n\“]\n”]
[:a “[:a \“user=> \“]\n”]

cgrand16:08:42

I should port this to unrepl which suffer from the same unbuffered verbosity issue

pesterhazy16:08:23

It flushes after 50ms?

cgrand17:08:44

yeah, it flushes every 50ms. Do you see any issue with that?

pesterhazy17:08:21

it could lead to a noticeable lag when used interactively

pesterhazy17:08:14

would lowering it to 10ms (or 5ms?) have any drawbacks?

cgrand18:08:26

it flushes every 50ms if no applicative flush occured (and there’s one right after prompt).

cgrand18:08:47

the only purpose is to merge together outputs. Actually we get one message for each call to .write.

cgrand18:08:40

in unrepl this is an issue only when the user has some print calls: in one print call e.g. (prn {:a 1 :b 2}) then the output is

[:out “{” 5]
[:out “:a” 5]
[:out ” ” 5]
[:out “1” 5]
[:out “, ” 5]
[:out “:b” 5]
[:out ” ” 5]
[:out “2” 5]
[:out “}” 5]
[:out “\n” 5]
[:eval nil 5]

cgrand18:08:33

To summarize: when printing a lot to :out (`:err` should be kept unbuffered as usual) the output may be differed by up to 50ms.

pesterhazy18:08:00

thanks for the explanation

cgrand18:08:00

I don’t think it will add any noticeable lag... unless you are doing a Zork speed run

pesterhazy18:08:46

upgrading unrepl to zork. Great idea

dominicm19:08:20

I count frames between character prints in order to measure the performance of my code. This completely breaks my workflow, could you please add an option to put it back without the flush please?

cgrand20:08:51

@dominicm for the most demanding users there's Mux Pro with 120Hz buttery-smooth printing. All messages are made from chars extracted from freshly mined Bitcoin blocks. Characters refills can be bought as in-app purchase.

pesterhazy20:08:37

where can i preorder?