Fork me on GitHub
#inf-clojure
<
2023-04-07
>
Jakub Šťastný16:04:56

Hey guys. I just installed inf-clojure and when I do inf-clojure-connect and point it to my local REPL at localhost / 5555, I get this:

Symbol's value as variable is void: inf-clojure-custom-repl-name
What's going on?

dpsutton16:04:12

that’s annoying. Can you debug it and see what’s going on? You can m-x toggle-debug-on-error and debug or get a stacktrace and see. I’ve got to stash some local changes but i’ll pull it down and see what’s up

dpsutton16:04:33

i see. that’s used and never defined

Jakub Šťastný16:04:20

-UUU:----F1  *Org Src  clojure ]*   All L4    <N>   (Clojure inf-cloj
  1 Debugger entered--Lisp error: (void-variable inf-clojure-$
  2   (or inf-clojure-custom-repl-name (if project-dir (forma$
  3   (let* ((project-dir (clojure-project-dir)) (process-buf$
  4   inf-clojure(("localhost" . 5555))
  5   inf-clojure-connect("localhost" 5555)
  6   funcall-interactively(inf-clojure-connect "localhost" 5$
  7   call-interactively(inf-clojure-connect record nil)
  8   command-execute(inf-clojure-connect record)
  9   execute-extended-command(nil "inf-clojure-connect" "inf$
 10   funcall-interactively(execute-extended-command nil "inf$
 11   call-interactively(execute-extended-command nil nil)
 12   command-execute(execute-extended-command)

Jakub Šťastný16:04:37

I think I'll just need to get the stable version.

dpsutton16:04:39

well short term you can (defvar inf-clojure-custom-repl-name nil)

dpsutton16:04:42

and it will work

dpsutton16:04:02

but we should raise an issue. someone recently committed some socket repl help and there were some changes so i guess this got left in

Jakub Šťastný16:04:14

I'll do it.

💪 2
Jakub Šťastný16:04:40

Anyway that defvar doesn't do it totally, there are more issues: let: Symbol's value as variable is void: inf-clojure-socket-repl-type I'll just report it as a bug and will use stable version.

dpsutton16:04:59

that’s frustrating

dpsutton16:04:19

and if you also defvar that?

Jakub Šťastný16:04:16

OK that gets me to inf-clojure--prompt-repl-type prompt (previously it failed after host/`port`).

Jakub Šťastný16:04:29

But ... I don't even expect this prompt.

Jakub Šťastný16:04:40

Like the REPL is running, isn't that the point of connect?

dpsutton16:04:50

have you told inf-clojure what type of repl you are using in some other way?

dpsutton16:04:17

the doc and source commands (and all of the others) depend on whether its a clojure, cljs, bb, planck, etc. repl

Jakub Šťastný16:04:27

I see, clearly I don't understand the prompt. Let me go with clojure and see...

dpsutton16:04:42

What is the text of the prompt?

Jakub Šťastný16:04:32

OK so the REPL is running.

Jakub Šťastný16:04:20

I can do C-x C-e to eval. Strangely it doesn't show the result in the current buffer, I have to switch to the REPL buffer manually. Am I too spoilt?

dpsutton16:04:46

inf-clojure does not try to hide stuff from you. It’s meant to be a way to interact with a repl

dpsutton16:04:57

it doesn’t automatically set the ns when you evaluate

Jakub Šťastný16:04:29

OK, perfect, I'll do some learning on that. Just wanted to check it's behaving how it should.

👍 2
Jakub Šťastný16:04:40

The other thing, if I want to connect from within Emacs to my custom REPL, I see there's inf-clojure-socket-repl which makes me do that...except it doesn't allow me to connect to a custom REPL (`clojure -X:repl-server` from my deps.edn). Thank God for Emacs patching, I just added it to inf-clojure-socket-repl-startup-forms:

(defvar inf-clojure-socket-repl-startup-forms
  '((custom-repl-server . "clojure -X:repl-server :port %d")
    ...other opts)
But that's clearly not a long-term solution. Is there a way to do this? All I want is that inf-clojure-socket-repl offers me clojure -X:repl-server.

dpsutton16:04:27

I was against this feature for exactly this reason

dpsutton16:04:42

i think you should just start your repl in a terminal with all of your usual options

dpsutton16:04:08

trying to figure out how to pass this information to inf-clojure so it knows how to pass this information to the CLI is such a pain

dpsutton16:04:20

and there’s so much documentation around the CLI that i think we should just use that

dpsutton16:04:52

especially if your startup is so nice: clj -X:repl-server :port 5000 and then inf-clojure-connect

dpsutton17:04:21

I don’t mean to be overly negative. Making inf-clojure work for everyone is great. I just see lots of downsides that you are immediately running into and no great general solutions

dpsutton17:04:40

but i think you can use inf-clojure-custom-startup

👍 2
Jakub Šťastný17:04:47

That's fine. For now I just want to learn how it works. I like Cider, but...no socket REPL, that's the thing.

dpsutton17:04:10

yeah. i’m a huge socket repl fan.

Jakub Šťastný17:04:54

Exactly 🙂 I'm not yet totally in the know, but I see the reasons and want to learn more!

dpsutton17:04:36

i love it because i can easily connect to a jar running in CI over ssh, a prod jar locally, or my local dev setup. And my tooling remains the same across all instances

Jakub Šťastný17:04:43

That's pretty cool.

dpsutton17:04:56

java -D<socket-repl-stuff> -jar my-project.jar clj -J-D<socket-repl-stuff> -A|-X|-M … use ssh to port forward and then connect to a jar running elsewhere, etc

Jakub Šťastný17:04:25

Does the inf-clojure-custom-startup actually work?

34 #+begin_src emacs-lisp :tangle .dir-locals.el
 35   ((nil
 36     ;; (inf-clojure-custom-startup . "clojure -X:repl-server")
 37     (inf-clojure-custom-startup . ("localhost" . 5555))
 38     (inf-clojure-custom-repl-type . clojure)))
 39 #+end_src
I have this, load the vars, confirm them being safe, do inf-clojure and it'd still ask me what do I want to connect to. Neither of these two forms "clojure -X:repl-server" or ("localhost" . 5555) seem to work.

dpsutton17:04:47

are you using inf-clojure-socket-repl ?

Jakub Šťastný17:04:24

inf-clojure-socket-repl is also unaffected by the vars.

dpsutton17:04:42

i can do

(setq inf-clojure-custom-startup "clojure -J-Dclojure.server.repl=\"{:port %d :accept clojure.core.server/repl}\" -A:grepl")
(setq inf-clojure-custom-repl-type 'clojure)
and then m-x inf-clojure-socket-repl and it starts up with my custom startup and sets the type

Jakub Šťastný17:04:08

That's bloody weird!

Jakub Šťastný17:04:26

@U11BV7MTK I evaluated these forms and it didn't work either.

dpsutton17:04:33

i’m doing some changes locally to make it work. i’m gonna send up a branch soon

🙏 2
Jakub Šťastný17:04:37

(I mean the forms you just sent.)

Jakub Šťastný17:04:58

Thanks, I'd be very grateful.

Jakub Šťastný21:04:46

Thanks @U11BV7MTK! Let me try that now.

Jakub Šťastný21:04:00

There are failing tests, but you've probably seen that.

dpsutton21:04:28

yeah. those tests have been failing for a while. probably should be removed

Jakub Šťastný21:04:03

I don't know what's going on. So I have the code from your PR. Verified by ag inf-clojure-custom-repl-name $(find ~/.emacs.d -name inf-clojure.el) -A2, it shows the code from the PR. Quit Emacs. Start Emacs. Nothing interesting in *Messages*. Let's try if my vars are being read:

(message inf-clojure-custom-startup)
; "clojure -X:repl-server"

(message inf-clojure-custom-repl-type)
; "clojure"
All looks good to me. But then I do inf-clojure-socket-repl and I get the interactive prompt Select Clojure socket REPL startup command again.

dpsutton21:04:27

two things. The custom startup needs to have a "%d" in it for where emacs gives it the port. It needs to assign the port to the startup so it knows what to connect to. And then the custom repl type should be 'clojure a symbol not a string

Jakub Šťastný21:04:07

If I have 'clojure I get this:

Debugger entered--Lisp error: (wrong-type-argument stringp clojure)
When I try to do (message inf-clojure-custom-repl-type).

dpsutton21:04:38

Debugger entered--Lisp error: (wrong-type-argument stringp bob)
  message(bob)

dpsutton21:04:49

you can’t (message 'bob) . message must take a string

Jakub Šťastný21:04:16

(Totally not used to Elisp.)

dpsutton21:04:25

(message (symbol-name 'bob))

dpsutton21:04:32

(no worries. it’s a weird language 🙂 )

Jakub Šťastný21:04:15

Now I can't print the command since it has "%d" in it and it expects an arg. But anyway I think I have the right value now.

Jakub Šťastný21:04:29

... and I'm still getting that interactive prompt.

dpsutton21:04:32

not sure i follow

Jakub Šťastný21:04:17

(message "clojure -X:repl-server :port %d")

Jakub Šťastný21:04:31

Because it expects argument for %d.

Jakub Šťastný21:04:58

(I just wanted to verify it had the right value.)

dpsutton21:04:06

does startup work?

dpsutton21:04:38

inf-clojure is gonna call (format cmd port) to check you can just do (message (format "clojure -X:repl-server :port %d" 5000))

dpsutton21:04:42

and use a dummy port

Jakub Šťastný21:04:51

OK checked, the values are 100% right.

Jakub Šťastný21:04:57

Yet it isn't working.

dpsutton21:04:25

can you tell what the alias repl-server is defined as?

Jakub Šťastný21:04:06

Same interactive prompt on both of inf-clojure and inf-clojure-socket-repl.

Jakub Šťastný21:04:12

8    {:repl-server
  9     {:exec-fn playground.repl/start-server
 10      :exec-args {:name "repl-server"
 11                  :port 5555
 12                  :accept playground.repl/repl
 13                  :server-daemon false}}}

dpsutton21:04:12

does everything work if you do

clj -X:repl-server :port 4567
and then inf-clojure-connect to localhost and 4567?

dpsutton21:04:28

just start it in a terminal and then connect to it

Jakub Šťastný21:04:15

I can run it like that, yes, it starts on the right port.

Jakub Šťastný21:04:24

And I can rlwrap nc localhost 4567 and it starts and responds.

dpsutton21:04:40

and what about inf-clojure-connect localhost 4567 or whatever port?

Jakub Šťastný21:04:43

Also responds. It did ask me REPL type, which it shouldn't, since I set the variable, but the REPL itself works, yes.

dpsutton21:04:58

ok. that’s good to know

dpsutton21:04:22

is playground.repl public? I’d like to try with your exact setup

Jakub Šťastný21:04:12

Happy to make it public, but I don't think there's anything interesting, because Emacs never even tries to start the command. The issue is before that.

Jakub Šťastný22:04:17

File src/playground/repl.clj

(ns playground.repl
  (:require [clojure.core.server :as s]))

(defn repl []
  (clojure.main/repl
    :init s/repl-init
    :read s/repl-read
    :print prn))

(defn start-server [{:keys [port] :as opts}]
  (println (str "~ Starting socket REPL on port " port "."))
  (println (str "  Connect: rlwrap nc localhost " port))
  (s/start-server opts))
And deps.edn
{:paths ["src"]
 :aliases
 {:repl-server
  {:exec-fn playground.repl/start-server
   :exec-args {:name "repl-server"
               :port 5555
               :accept playground.repl/repl
               :server-daemon false}}}}

Jakub Šťastný22:04:23

Really the wrapper doesn't do anything yet. It's my starting point for exploring socket REPLs that I want to play with once I get this working.

dpsutton22:04:29

ok works for me from a terminal. let me try starting it

dpsutton22:04:46

ah i know why. this feature expects to see a repl prompt to know when the repl is ready. and you never print a repl prompt

Jakub Šťastný22:04:14

But are you sure? To me there's no indication it ever tries to start a process.

dpsutton22:04:55

yes i’m sure. It has a process filter that waits for startup to complete so it knows the repl is ready. it could be delayed due to downloading dependencies, etc so it needs to know the repl is up and running

Jakub Šťastný22:04:56

It goes to display the prompt straight away, there's no lag like if it'd be waiting.

dpsutton22:04:11

no prompt at all:

Jakub Šťastný22:04:30

It didn't occur to me it'd be necessary haha.

dpsutton22:04:40

kinda why i don’t like this stuff

dpsutton22:04:46

change it to this:

(defn start-server [{:keys [port] :as opts}]
  (println (str "~ Starting socket REPL on port " port "."))
  (println (str "  Connect: rlwrap nc localhost " port))
  (future (s/start-server opts))
  (repl)
  )

dpsutton22:04:27

start-server is a loop looking for connections so the repl never prints as the start-server function never “finishes”. So give it its own thread and then start up a repl

dpsutton22:04:05

note, it is waaaaaaay easier to let Clojure do this for you. Which is what that default connection string is doing:

"clojure -J-Dclojure.server.repl=\"{:port %d :accept clojure.core.server/repl}\""
that is gonna just start up the normal clojure program (which defaults to a repl, and also starts the server on its own thread listening for socket connections. What you are doing is saying “I’m the main entry point. and you should open up a socket and listen for connections” so it never starts the repl, and therefore emacs never knows it is ready

Jakub Šťastný22:04:57

OK thanks a lot Dan, I really appreciate your help 🙏:skin-tone-3:

dpsutton22:04:13

my pleasure. Are you up and running now?

Jakub Šťastný22:04:47

It shows the right thing:

~ Starting socket REPL on port 4567.
  Connect: rlwrap nc localhost 4567
user=>
But inf-clojure-socket-repl still doesn't respond to that. I want to try with the default clojure command you pasted first and see.

dpsutton22:04:03

and this is why that system property way to start a socket repl is so nice: -J-Dclojure.server.repl you can have other entry points. Want reveal to startup and give you that nice interaction? clj -J-D… -M reveal. Have a -X startup? You can start the socket repl and have the entry point you want

dpsutton22:04:07

weird it is working for me

Jakub Šťastný22:04:17

I assume you start with inf-clojure-socket-repl, correct?

dpsutton22:04:38

yup. i get asked zero questions and after a second the repl buffer pops up

Jakub Šťastný22:04:52

OK so something else must be going on still. Even with (inf-clojure-custom-startup . "clojure -J-Dclojure.server.repl=\"{:port %d :accept clojure.core.server/repl}\" -A:grepl") property it still doesn't work.

dpsutton22:04:11

i just restarted emacs, evaled

(setq inf-clojure-custom-startup "clojure -X:repl-server :port %d")
(setq inf-clojure-custom-repl-type 'clojure)
and then inf-clojure-socket-repl

dpsutton22:04:16

are you sure you have my branch?

dpsutton22:04:24

can you look at inf-clojure.el?

Jakub Šťastný22:04:40

ag inf-clojure-custom-repl-name $(find ~/.emacs.d -name inf-clojure.el) -A2
521:(defvar inf-clojure-custom-repl-name nil
522-  "A string to be used as the repl buffer name.")
523-
--
831:                               inf-clojure-custom-repl-name
832-                               (if project-dir
833-                                   (format "inf-clojure %s" (inf-clojure--project-name project-dir))

Jakub Šťastný22:04:49

Right, that's the new code.

dpsutton22:04:25

can you open that inf-clojure.el file and tell me what is on line 962?

Jakub Šťastný22:04:33

(created-repl-buffer (inf-clojure-connect host port :suppress-message)))

dpsutton22:04:09

ok. that’s what i have. I wonder what could be different between our setups

Jakub Šťastný22:04:35

Yeah me too. It looks like a very straightforward thing.

dpsutton22:04:15

What is the value of inf-clojure-custom-startup you are using?

Jakub Šťastný22:04:45

"clojure -J-Dclojure.server.repl=\"{:port %d :accept clojure.core.server/repl}\" -A:grepl"

Jakub Šťastný22:04:28

OK...so I find something out:

Jakub Šťastný22:04:39

I use Org-mode for everything. Great for dumb people with loosy memory, I have code and notes together. (Also allows for grouping things logically and other things, which I really appreciate.)

Jakub Šťastný22:04:53

I normally edit code in a Orgmode narrow (`C-C '`). That gives me all that's in the current source block as a new buffer. I edit it, run CLJ stuff there and then when I'm happy, I close it by C-c ' and it saves the update into the main buffer.

Jakub Šťastný22:04:14

If I open the actual tangled CLJ source file, it works there.

Jakub Šťastný22:04:25

In the Orgmode narrow buffer, it doesn't.

dpsutton22:04:43

what doesn’t work?

Jakub Šťastný22:04:27

* Deps

Ref [[ and CLI guide: socket REPL]].

#+begin_src clojure :tangle deps.edn
  {:paths ["src"]
   :aliases
   {:repl-server
    {:exec-fn playground.repl/start-server
     :exec-args {:name "repl-server"
                 :port 5555
                 :accept playground.repl/repl
                 :server-daemon false}}}} ; How to run as a daemon?
#+end_src

Ref [[.

#+begin_src emacs-lisp
  (setq inf-clojure-custom-startup "clojure -X:repl-server :port %d")
  (setq inf-clojure-custom-repl-type 'clojure)

  (message (format inf-clojure-custom-startup 5000))
  (message (symbol-name inf-clojure-custom-repl-type))
#+end_src

Eval this, then ~inf-clojure-socket-repl~.



Ref [[.
#+begin_src emacs-lisp :tangle .dir-locals.el
  ((nil
    ;(inf-clojure-custom-startup . "clojure -X:repl-server :port %d")
    (inf-clojure-custom-startup . "clojure -J-Dclojure.server.repl=\"{:port %d :accept clojure.core.server/repl}\" -A:grepl")
    ;(inf-clojure-custom-startup . ("localhost" . 5555))
    (inf-clojure-custom-repl-type . clojure)

    ;; (inf-clojure-prompt-read-only t)
    ;; (inf-clojure-repl-use-same-window t)
    ))
#+end_src

#+begin_src clojure :tangle src/playground/repl.clj :mkdirp yes
  (ns playground.repl
    (:require [clojure.core.server :as s]))

  (defn repl []
    (clojure.main/repl
      :init s/repl-init
      :read s/repl-read
      :print prn))

  (defn start-server [{:keys [port] :as opts}]
    (println (str "~ Starting socket REPL on port " port "."))
    (println (str "  Connect: rlwrap nc localhost " port))
    (future (s/start-server opts))
    (repl))
#+end_src

** Usage
#+begin_src sh
  clojure -X:repl-server
  clojure -X:repl-server :port 51234
  rlwrap nc localhost 5555
#+end_src

#+begin_src clojure :tangle src/playground.clj :mkdirp yes
  (filter odd?)
  (range 10)
  (range)
#+end_src

Jakub Šťastný22:04:50

1. If I go to the last code block that tangles into src/playground.clj, open it via C-c ' and try to connect to the REPL there using inf-clojure-socket-repl, no luck. 2. Same thing works fine if I open src/playground.clj manually as its own buffer.

Jakub Šťastný22:04:33

So this is related to that setup. Normally other CLJ tools work in that narrow Orgmode buffer, including Clojure mode, Lispy and Cider as well.

dpsutton22:04:56

no idea. ¯\(ツ)

Jakub Šťastný22:04:10

No don't worry about it, I'll have a look.

Jakub Šťastný22:04:15

Just filling you in.

dpsutton22:04:27

yeah. step through the code. You’ll need to debug it to see where it goes off the rails

dpsutton22:04:34

maybe determining the project root

Jakub Šťastný22:04:10

Project root could be a culprit

Jakub Šťastný22:04:24

OK, at least I'll learn some Emacs debugging.

Jakub Šťastný22:04:53

The workaround is to first open a .clj file, inf-clojure-socket-repl, then close the source file and go back to the normal Org mode literary programming workflow. Will debug it at some point, but this works for now and I'm more interested in socket REPLs than in Emacs, so I'll leave it at that for the time being.