This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-03-09
Channels
- # alda (5)
- # aleph (10)
- # bangalore-clj (1)
- # beginners (168)
- # cider (68)
- # cljs-dev (263)
- # clojars (4)
- # clojure (66)
- # clojure-brasil (25)
- # clojure-china (1)
- # clojure-dusseldorf (1)
- # clojure-greece (4)
- # clojure-italy (3)
- # clojure-russia (4)
- # clojure-spec (12)
- # clojure-uk (16)
- # clojurescript (36)
- # community-development (12)
- # cursive (9)
- # data-science (1)
- # datascript (8)
- # datomic (20)
- # defnpodcast (6)
- # emacs (2)
- # figwheel (2)
- # fulcro (51)
- # graphql (62)
- # immutant (14)
- # keyboards (1)
- # lein-figwheel (10)
- # leiningen (5)
- # lumo (15)
- # off-topic (4)
- # onyx (3)
- # pedestal (4)
- # portkey (13)
- # protorepl (1)
- # re-frame (8)
- # reagent (2)
- # reitit (4)
- # shadow-cljs (71)
- # spacemacs (7)
- # specter (33)
- # sql (9)
- # unrepl (75)
- # vim (7)
Hmm.... the repl buffer should probably not do read tracking. However, then some special treatment of prompts is necessary.
Eg. user=> (read) :foo (read)<enter> would result in: user=> (read) :foo (read) :foo user=> <cursor here in stdin mode> So there is an empty prompt. However it must be ignored. So it is a bit difficult because the buffer is one channel. Not two like a terminal. Maybe it just works. Maybe it need some special magic. I have to think about this.
-.- encountered the first problem where vim and clojure disagree on character count....
Non-ascii. Vim has strchars and strlen. The latter gives bytes the former characters. I thought I needed that, but the failed now. Strlen however was correct. -.- Why can't we have cookies?
Maybe it's not a problem. In this case it wasn't. I need to check this. How is the wire encoding chosen?
ouch just checked the code: I really thought that clojure.core.server was forcing UTF-8. No. Platform default. Argh!
Vim actually also has file and term encoding settings. For me these are all hardwired to utf-8.
It has a iconv(). So I could also convert things on the vim side. But I prefer the model T approach.
Previously people (at least @volrath and @kotarak) had requested a way to set the eval-id because having to track :read
messages to find the matching id was cumbersome.
Now since there’s always a prompt before an eval (previously (+ 1 2)(+ 3 4)\n
would have triggered two :eval
s but one :prompt
, the prompt is respobsible for allocating the eval-id.
synchornizing is thus easier: you know that there’s nothing in flight when prompt offset matches the sent-chars count of the client (better add a tolerance for whitespaces)
correct me if I'm wrong, but now if we want to produce the same output than a regular repl, the clients would have to know that some prompt
messages should be ignored.
i.e.
$> clj
Clojure 1.9.0
user=> (+ 1 2)(+ 3 4)
3
7
user=>
but with these extra prompt
messages, the client would print a prompt between the first result 3
and the second 7
$> clj
Clojure 1.9.0
user=> (+ 1 2)(+ 3 4)
3
user=>
7
user=>
Yes, it behaves like
$ clj
Clojure 1.9.0
user=> (clojure.main/repl :need-prompt (constantly true))
user=> (+ 1 2)(+ 3 4)
3
user=> 7
user=>
[:prompt {:file nil, :line 1, :column 1, :offset 0, clojure.core/*ns* #unrepl/ns user, clojure.core/*warn-on-reflection* false} 1]
(+ 1 2)(+ 3 4)
[:read {:file “unrepl-reader-684”, :from [1 1], :to [1 8], :offset 0, :len 7} 1]
[:started-eval {:actions {:interrupt (unrepl.repl$NPYB29j9QDmbJ9ILAyMl3uHuLOs/interrupt! :session683 1), :background (unrepl.repl$NPYB29j9QDmbJ9ILAyMl3uHuLOs/background! :session683 1)}} 1]
[:eval 3 1]
[:prompt {:file nil, :line 1, :column 8, :offset 7, clojure.core/*ns* #unrepl/ns user, clojure.core/*warn-on-reflection* false} 2]
[:read {:file “unrepl-reader-684", :from [1 8], :to [1 15], :offset 7, :len 7} 2]
[:started-eval {:actions {:interrupt (unrepl.repl$NPYB29j9QDmbJ9ILAyMl3uHuLOs/interrupt! :session683 2), :background (unrepl.repl$NPYB29j9QDmbJ9ILAyMl3uHuLOs/background! :session683 2)}} 2]
[:eval 7 2]
[:prompt {:file nil, :line 1, :column 15, :offset 14, clojure.core/*ns* #unrepl/ns user, clojure.core/*warn-on-reflection* false} 3]
@volrath are you just making sure you understand it or is it against your repl aesthetics?
I simply check if there is a prompt and whether the command is empty. If so the spurious prompt is removed. There is a race condition though.
Vim is async. I have to add a prompt because I don't know what else is coming. The second form then starts. And the spurious prompt is removed. However the event handling is async. So the user might already have typed something. The chance that this happens is pretty low. Or so I should hope.
legacy behaviour is “you get a prompt when at the start of a line” so
(+ 1
2) (+ 3 4)
triggers only one final promptFWIW my own repl aesthetics: I see the repl split in two frames: upper frame is the log, divider holds the prompt info, bottom frame is the input buffer. Having actual input split in chunks (in the log) according to eval is ok for me.
That's even more funky in vim. I rather keep one window with one buffer. Complicated enough.
This doesn't help. Since I now have a eval operator, the user might choose to send any span of text for evaluation. In particular multiple forms separated by empty lines. So I will get multiple :column one prompts. So I still need to track the read count. But that's ok. I think that works.
As I said: read tracking works! If you find that too funky on the unrepl side, there is no need to have it. Clients can do it, if they need it.
I just wanted to point out, that the :column one approach might be insufficient. Depending on your inputs.
Now:
[:prompt {:file nil, :line 1, :column 1, :offset 0, clojure.core/*ns* #unrepl/ns user, clojure.core/*warn-on-reflection* false} 1]
(+ 1 2)(+ 3 4)
[:read {:file "unrepl-reader-683", :from [1 1], :to [1 8], :offset 0, :len 7} 1]
[:started-eval {:actions {:interrupt (unrepl.repl$jr7rtNzCvE2Cb_3TntSHIMlqPCY/interrupt! :session682 1), :background (unrepl.repl$jr7rtNzCvE2Cb_3TntSHIMlqPCY/background! :session682 1)}} 1]
[:eval 3 1]
[:prompt {:file nil, :line 1, :column 8, :offset 7, clojure.core/*ns* #unrepl/ns user, clojure.core/*warn-on-reflection* false} 2]
[:read {:file "unrepl-reader-683", :from [1 8], :to [1 15], :offset 7, :len 7} 2]
[:started-eval {:actions {:interrupt (unrepl.repl$jr7rtNzCvE2Cb_3TntSHIMlqPCY/interrupt! :session682 2), :background (unrepl.repl$jr7rtNzCvE2Cb_3TntSHIMlqPCY/background! :session682 2)}} 2]
[:eval 7 2]
[:prompt {:file nil, :line 1, :column 15, :offset 14, clojure.core/*ns* #unrepl/ns user, clojure.core/*warn-on-reflection* false} 3]
; THE TWO LINES BELOW ARE WHAT CHANGED
[:read {:file "unrepl-reader-683", :from [1 15], :to [2 1], :offset 14, :len 1} 3]
[:prompt {:file nil, :line 2, :column 1, :offset 15, clojure.core/*ns* #unrepl/ns user, clojure.core/*warn-on-reflection* false} 4]
Now:
[:prompt {:file nil, :line 1, :column 1, :offset 0, clojure.core/*ns* #unrepl/ns user, clojure.core/*warn-on-reflection* false} 1]
(+ 1 2)(+ 3 4)
[:read {:file "unrepl-reader-683", :from [1 1], :to [1 8], :offset 0, :len 7} 1]
[:started-eval {:actions {:interrupt (unrepl.repl$L5y82Z_WyPDOudROXJCUgcOs6ZY/interrupt! :session682 1), :background (unrepl.repl$L5y82Z_WyPDOudROXJCUgcOs6ZY/background! :session682 1)}} 1]
[:eval 3 1]
[:prompt {:file nil, :line 1, :column 8, :offset 7, clojure.core/*ns* #unrepl/ns user, clojure.core/*warn-on-reflection* false} 2]
[:read {:file "unrepl-reader-683", :from [1 8], :to [1 15], :offset 7, :len 7} 2]
[:started-eval {:actions {:interrupt (unrepl.repl$L5y82Z_WyPDOudROXJCUgcOs6ZY/interrupt! :session682 2), :background (unrepl.repl$L5y82Z_WyPDOudROXJCUgcOs6ZY/background! :session682 2)}} 2]
[:eval 7 2]
[:prompt {:file nil, :line 1, :column 15, :offset 14, clojure.core/*ns* #unrepl/ns user, clojure.core/*warn-on-reflection* false} 3]
; NO MORE :READ HERE
[:prompt {:file nil, :line 2, :column 1, :offset 15, clojure.core/*ns* #unrepl/ns user, clojure.core/*warn-on-reflection* false} 4]
With more prompts, :read
messages are almost obsolete (its data could be derived by comparing two consecutive prompts). The only thing that it has for it is that you get the data earlier (you don’t have to wait until end of eval)
(+
1
2
3)
[:read {:file “unrepl-reader-683”, :from [2 1], :to [5 4], :offset 15, :len 12} 4]
[:started-eval {:actions {:interrupt (unrepl.repl$L5y82Z_WyPDOudROXJCUgcOs6ZY/interrupt! :session682 4), :background (unrepl.repl$L5y82Z_WyPDOudROXJCUgcOs6ZY/background! :session682 4)}} 4]
[:eval 6 4]
[:prompt {:file nil, :line 5, :column 4, :offset 27, clojure.core/*ns* #unrepl/ns user, clojure.core/*warn-on-reflection* false} 5]
[:prompt {:file nil, :line 6, :column 1, :offset 28, clojure.core/*ns* #unrepl/ns user, clojure.core/*warn-on-reflection* false} 6]
`