What is the minimal Emacs config for practical Clojure development?

1,218 views
Skip to first unread message

Austin Haas

unread,
Jul 1, 2018, 11:41:23 PM7/1/18
to Clojure
I don't want to use a package manager with Emacs.

Should I launch a REPL outside of Emacs, then connect to it? Using the CLI tools (i.e., from the command line: clojure -J-Dclojure.server.repl="{:port 5555 :accept clojure.core.server/repl}")?

Can I launch a REPL from within Emacs?

I've been using inf-clojure and clojure-mode with the following elisp in my .emacs:

(add-to-list 'load-path "~/.emacs.d/site-lisp/third-party/clojure-mode/")
(require 'clojure-mode)
(add-to-list 'load-path "~/.emacs.d/site-lisp/third-party/inf-clojure/")
(load-file "~/.emacs.d/site-lisp/third-party/inf-clojure/inf-clojure.el")
(add-hook 'clojure-mode-hook #'inf-clojure-minor-mode)
(setf inf-clojure-lein-cmd "lein run -m clojure.main")

and C-c C-z to start a REPL, but I get noise in the REPL, including repeated prompts, and (seemingly) random linebreaks in large output.

What's the state of the art for a simple, practical Emacs setup for Clojure?

Łukasz Korecki

unread,
Jul 3, 2018, 1:42:00 AM7/3/18
to Clojure
Hi!

I've recently switched to Monroe - https://github.com/sanel/monroe 
Its feature set is quite limited, and it boils down to:

- start a nREPL server
- connect to it
- a REPL buffer is created inside of Emacs
- evaluate forms

I've added a tiny bit of config on my side which adds a Clojure scratch buffer https://github.com/lukaszkorecki/cult-leader/blob/master/settings/lk/clojure.el#L26-L44
and that's pretty much it.


Łukasz

Daniel Compton

unread,
Jul 3, 2018, 3:36:42 AM7/3/18
to clo...@googlegroups.com
Not sure exactly how minimal you're looking for but I like Prelude. It's maintained by Bozhidar Batsov, who also maintains CIDER, so it works well for Clojure development.

--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Jérémie Grodziski

unread,
Jul 3, 2018, 11:21:13 AM7/3/18
to Clojure
I like very much Spacemacs with the Clojure layer for its discoverability and "out of the box" configuration.
Ok it's a kind of a package manager, but once I switch to Spacemacs I've never look back.

Austin Haas

unread,
Jul 3, 2018, 11:46:05 AM7/3/18
to Clojure
Thanks for the replies.

I only want a stable REPL, integrated with Emacs, and nothing else.

Łukasz, why did you switch to Monroe? What do you prefer about it?

Didier

unread,
Jul 3, 2018, 11:25:35 PM7/3/18
to Clojure
There's also inf-clojure, which is pretty minimal.

Łukasz Korecki

unread,
Jul 4, 2018, 7:47:13 AM7/4/18
to Clojure
If I'm not mistaken inf-clojure works best if you use the socket REPL. 
All our projects have a nREPL server embedded so  Monroe was a better fit for my workflow.

Nothing against inf-clojure, it works great!

Łukasz

Austin Haas

unread,
Jul 5, 2018, 1:51:02 PM7/5/18
to Clojure

I tried Monroe, yesterday. It seems to work as advertised. I didn't have any issues. It's nice that "jump to definition" works out of the box. It does not appear to support Eldoc, so no help with function signatures.

This is the Emacs config I'm currently using: 

;;; clojure-mode

(add-to-list 'load-path "~/.emacs.d/site-lisp/third-party/clojure-mode/")
(require '
clojure-mode)
(add-hook 'clojure-mode-hook 'rainbow-delimiters-mode)
(add-hook 'clojure-mode-hook 'paredit-mode)
(add-hook 'clojure-mode-hook 'hs-minor-mode)
(add-hook 'clojure-mode-hook #'eldoc-mode)

;;; REPL

;; Monroe

(add-to-list 'load-path "~/.emacs.d/site-lisp/third-party/monroe/")
(require '
monroe)
(add-hook 'clojure-mode-hook 'clojure-enable-monroe)
(setf monroe-detail-stacktraces 'true)

I went on to include Figwheel. 

I created a new project using `lein new figwheel my-project` (which provides the fig-start and cljs-repl functions), and then entered the following commands to set up a Clojurescript dev environment: 

M-x monroe-nrepl-server-start
M-x monroe
(fig-start)
(cljs-repl)

On my machine, those 4 steps take about 30 seconds to run. The first takes 18 seconds, and the rest only take about a second each, but the whole process ends up taking close to 30.

Figwheel seems to work great, but I couldn't figure out how to evaluate code in a library dependency and have it updated in the running system. I can evaluate functions, but the new definitions don't appear to be called by the main code. I might be misunderstanding how this is supposed to work; I don't know if it's a Figwheel issue or a Monroe issue or my mistake. But to work around that, and to fix other issues preventing a clean initial compilation, I had to restart the REPL a few dozen times, which was tedious.

I'm posting this information in case it is useful to someone else who is trying to discover the current state-of-the-art with running Clojure in Emacs in a straightforward, minimal way. I'm also hoping that people will reply with comments and suggested improvements. (FWIW, I've been using Emacs full-time for about 20 years, Clojure full-time for about 7 years, and Common Lisp for 5+ years before that, so I'm not new to REPL-driven development in Emacs.)


rob

unread,
Jul 5, 2018, 2:19:21 PM7/5/18
to Clojure
If ClojureScript repl integration works smoothly out of the box then that's already one reason to use it over Cider...  (This is not a jab at Cider, just a statement of fact that Cider's support for ClojureScript development has so far been lacking, IME)

Gary Trakhman

unread,
Jul 5, 2018, 3:07:13 PM7/5/18
to clo...@googlegroups.com
I'm not sure the desires for lightweight clojure-emacs integration and any CLJS integration are yet sympathetic.  Figwheel is a pretty complex piece of software. For example, see my issue that has been languishing for almost a year and hints at greater problems with the compiler integration: https://github.com/bhauman/lein-figwheel/issues/593 .  From my perspective, this is more due to coupling of the REPL to the compiler itself than a problem with figwheel.

But I was surprised when the thread went in this direction just from reasons I think someone might want to not use cider, fast startup time, less stuff to go wrong.  CLJS adds that back unless it's gotten significantly better since the last time I tried.

Austin Haas

unread,
Jul 5, 2018, 4:01:14 PM7/5/18
to Clojure
Gary, I had tried Figwheel a couple years ago and I had a positive experience, so that was the next thing I reached for.

I just want a practical dev environment, for both Clojure and Clojurescript. To me, that means simple and stable. I definitely want fewer things that can go wrong, but if I can install a package by cloning a repo and adding a few lines of elisp, and it works, I'm happy. I don't care how complex it is. If it causes my REPL to hang, prints out control characters, regularly breaks after updates, etc., then I'd rather drop down to something simpler, with fewer features.

For Clojurescript, I've used lein-cljsbuild in the past. That seemed to work well. I know I've connected to a REPL running in the browser before, but I don't remember it being useful enough to bother with. I don't think I knew how to write "reloadable code", then, though.

I would love to hear how people do Clojurescript development today, especially if they aren't using Figwheel.
Message has been deleted

Andrea Richiardi

unread,
Jul 5, 2018, 7:32:58 PM7/5/18
to Clojure


On Thursday, July 5, 2018 at 1:01:14 PM UTC-7, Austin Haas wrote:
Gary, I had tried Figwheel a couple years ago and I had a positive experience, so that was the next thing I reached for.

I just want a practical dev environment, for both Clojure and Clojurescript. To me, that means simple and stable. I definitely want fewer things that can go wrong, but if I can install a package by cloning a repo and adding a few lines of elisp, and it works, I'm happy. I don't care how complex it is. If it causes my REPL to hang, prints out control characters, regularly breaks after updates, etc., then I'd rather drop down to something simpler, with fewer features.

 
There is one more trick though.

The new cljs.main allows you to have a socket repl for ClojureScript. This can then be used with `inf-clojure`. It will not be fancy and probably things will be broken though...the code path has not been seen much love. I did some experimentation and it definitely works - quite smoothly in fact - but I have never have time to make it "production" ready :)

So this does not actually answers the question, just wanted to put it out there - sorry!

Daniel

unread,
Jul 6, 2018, 1:19:11 AM7/6/18
to Clojure
Luminus has a leiningen template which works out-of-the-box with Cider and figwheel. Just (start-fw) and (cljs) inside the repl.

It would be nice if we could have both repls open simultaneously within emacs, but everything was super unreliable the last time I tried that.

Austin Haas

unread,
Jul 6, 2018, 1:32:02 PM7/6/18
to Clojure
This is good, relevant information. Thank you, Andrea.

Austin Haas

unread,
Jul 6, 2018, 2:18:56 PM7/6/18
to Clojure
I spent a couple more hours working with Monroe and Figwheel. I still can't figure out how to use the REPL. After trying to evaluate a few expressions, Emacs gets completely locked up spewing the following error message 1000s of times: 

clojure.lang.ExceptionInfo: Arguments to require must be quoted. Offending spec: (symbol (namespace (quote clojure.repl/pst))) at line 1 <cljs repl> {:file "<cljs repl>", :line 1, :column 5, :root-source-info {:source-type :fragment, :source-form (do (require (symbol (namespace (quote clojure.repl/pst)))) (clojure.repl/pst *e))}, :tag :cljs/analysis-error}

I've switched back to inf-clojure and Figwheel with the following config:

(add-to-list 'load-path "~/.emacs.d/site-lisp/third-party/inf-clojure/")
(require 'inf-clojure)
(setf inf-clojure-lein-cmd "lein run -m clojure.main")
(add-hook 'clojure-mode-hook #'inf-clojure-minor-mode)
(add-hook 'inf-clojure-mode-hook #'eldoc-mode)

That seems to work, but I see something like this in the minibuffer every time I move the cursor, with or without eldoc mode enabled:

def: (:arglists^[[0m
  ^[[36m3^[[0m  ^[[36m(clojure.core/meta^[[0m
  ^[[36m4^[[0m  ^[[36m(clojure.core/resolve^[[0m
  ^[[36m5^[[0m  ^[[36m(clojure.core/read-string "def")

Does "lein run -m clojure.main" create a socket REPL?

I followed the instructions for inf-clojure for a "Clojure Command Line Socket REPL" (https://github.com/clojure-emacs/inf-clojure#clojure-command-line-socket-repl), but then (fig-start) is not found.

I followed the instructions for inf-clojure for a "Leiningen Socket REPL" (https://github.com/clojure-emacs/inf-clojure#leiningen-socket-repl), and that produces results like with "lein run -m clojure.main"; it works, but I get the "eldoc" garbage in the minibuffer. AFAICT, the eldoc problem doesn't occur until I run (cljs-repl).

Any insight greatly appreciated. 




Andrea Richiardi

unread,
Jul 6, 2018, 7:43:14 PM7/6/18
to Clojure

On Friday, July 6, 2018 at 11:18:56 AM UTC-7, Austin Haas wrote:
I spent a couple more hours working with Monroe and Figwheel. I still can't figure out how to use the REPL. After trying to evaluate a few expressions, Emacs gets completely locked up spewing the following error message 1000s of times: 


I guess you are pioneering this so don't give up! :D

The problem with socket REPL is that you need to make sure that it is "dumb enough". Make sure to read these two - sorry if you've seen it already:


That is why I was trying only cljs.main at some point. Less things involved. 
Message has been deleted

Andrea Richiardi

unread,
Jul 6, 2018, 7:50:57 PM7/6/18
to Clojure
Ok this command will open a socket REPL directly in cljs.user:

clojure -J-Dclojure.server.repl="{:port ${1:-5555} :accept cljs.server.node/repl}" -R:cljs-canary  -m cljs.main -re node -r

You need the right deps.edn aliases - then you will be able to nc localhost 5555 or inf-clojure-connect to it.

Andrea Richiardi

unread,
Jul 6, 2018, 7:59:14 PM7/6/18
to Clojure
That seems to work, but I see something like this in the minibuffer every time I move the cursor, with or without eldoc mode enabled:

def: (:arglists^[[0m
  ^[[36m3^[[0m  ^[[36m(clojure.core/meta^[[0m
  ^[[36m4^[[0m  ^[[36m(clojure.core/resolve^[[0m
  ^[[36m5^[[0m  ^[[36m(clojure.core/read-string "def")

Does "lein run -m clojure.main" create a socket REPL?

I followed the instructions for inf-clojure for a "Clojure Command Line Socket REPL" (https://github.com/clojure-emacs/inf-clojure#clojure-command-line-socket-repl), but then (fig-start) is not found.

I followed the instructions for inf-clojure for a "Leiningen Socket REPL" (https://github.com/clojure-emacs/inf-clojure#leiningen-socket-repl), and that produces results like with "lein run -m clojure.main"; it works, but I get the "eldoc" garbage in the minibuffer. AFAICT, the eldoc problem doesn't occur until I run (cljs-repl).

Any insight greatly appreciated. 

Sorry I am guilty of not having read the whole thing - can you please open an issue in inf-clojure so that we can track it?

Austin Haas

unread,
Jul 7, 2018, 2:54:15 PM7/7/18
to Clojure
Yesterday, I followed the excellent "Clojurescript Quick Start Guide" (https://clojurescript.org/guides/quick-start). Everything worked as expected. They did a great job of making it as minimal as possible.

After that, I followed the "Emacs and Inferior Clojure Interaction Mode" guide (https://clojurescript.org/tools/emacs-inf). That's a nice guide, too. I had one issue: the instructions are out of date because inf-clojure removed the run-clojure alias for the inf-clojure function. I submitted a patch: https://github.com/clojure/clojurescript-site/pull/246

Currently, I'm running with Emacs, inf-clojure, and lein-cljsbuild. It seems to be working well. I don't have live code reloading, like Figwheel.

This is the function I'm using in my .emacs to launch the repl: 

(defun cljs-browser-repl ()
  (interactive)
  (inf-clojure "lein trampoline run -m clojure.main repl.clj"))

And the contents of repl.clj:

(require '[cljs.repl :as repl])
(require '[cljs.repl.browser :as browser])  ;; require the browser implementation of IJavaScriptEnv
(def env (browser/repl-env :static-dir ["." "out/" "resources/public/"])) ;; create a new environment
(repl/repl env) ;; start the REPL

Today, for unknown reasons, I'm no longer getting the "def: (:arglists^[[0m..." messages in my minibuffer, but instead I'm seeing two different errors when I put the cursor in an expression:

WARNING: Use of undeclared Var cljs.user/Throwable at line 6 <cljs repl>
clojure.lang.ExceptionInfo: Assert failed: Argument to resolve must be a quoted symbol
(core/and (seq? quoted-sym) (= (quote quote) (first quoted-sym))) at line 4 <cljs repl> {:file "<cljs repl>", :line 4, :column 2, :root-source-info {:source-type :fragment, :source-form (try (:arglists (clojure.core/meta (clojure.core/resolve (clojure.core/read-string "ClojureScript")))) (catch Throwable t nil))}, :tag :cljs/analysis-error}

This usually pops up in the minibuffer as: defn: (core/and (seq? quoted-sym)), but fortunately the full message went to the REPL once. Note that this is the same error I was when using Monroe instead of inf-clojure.

The other message I see is: 

ReferenceError: planck is not defined
(<NO_SOURCE_FILE>)

which pops up in the minibuffer as: defn: (<NO_SOURCE_FILE>)

I also got this error once when trying to get the docstring for a var:

WARNING: No such namespace: lumo.repl, could not locate lumo/repl.cljs, lumo/repl.cljc, or JavaScript source providing "lumo.repl" at line 1 <cljs repl>
WARNING: Use of undeclared Var lumo.repl/doc at line 1 <cljs repl>
WARNING: Can't take value of macro cljs.core/declare at line 1 <cljs repl>
ReferenceError: lumo is not defined
(<NO_SOURCE_FILE>)

To my knowledge, I'm not using lumo or planck.

Andrea, do you still think these are issues with inf-clojure?

Austin Haas

unread,
Jul 7, 2018, 2:55:14 PM7/7/18
to Clojure
I tried this, changing node to browser, like so: 

clojure -J-Dclojure.server.repl="{:port ${1:-5555} :accept cljs.server.browser/repl}" -cljs-canary  -m cljs.main -re browser -r

That starts a REPL in my terminal, but when I try to connect to it from Emacs, using C-c M-c RET localhost RET 5555, I get the following in my Emacs *inf-clojure* buffer:

Process inf-clojure connection broken by remote peer

and the following the terminal REPL:

Exception in thread "Clojure Connection repl 1" java.lang.RuntimeException: Unable to resolve symbol: PrintWriter-on in this context, compiling:(cljs/core/server.clj:81:29)

Austin Haas

unread,
Jul 7, 2018, 3:04:44 PM7/7/18
to Clojure

I shouldn't have said that two of those errors were the same. They're different, but they both mention unquoted symbols.

Monroe

clojure.lang.ExceptionInfo: Arguments to require must be quoted. Offending spec: (symbol (namespace (quote clojure.repl/pst))) at line 1 <cljs repl> {:file "<cljs repl>", :line 1, :column 5, :root-source-info {:source-type :fragment, :source-form (do (require (symbol (namespace (quote clojure.repl/pst)))) (clojure.repl/pst *e))}, :tag :cljs/analysis-error}

inf-clojure

Austin Haas

unread,
Jul 7, 2018, 5:21:18 PM7/7/18
to Clojure
I've determined that the previously mentioned errors are related to incompatibilities with inf-clojure and clojurescript.

I filed a bug, and a workaround, with inf-clojure here: https://github.com/clojure-emacs/inf-clojure/issues/150

Austin Haas

unread,
Jul 9, 2018, 12:25:36 AM7/9/18
to Clojure

Quick update. 

After a reboot, my REPL starts up much faster (~3-4 seconds) than I reported above. Sorry for the noise.

I started adding CLJS support to inf-clojure: https://github.com/austinhaas/inf-clojure/tree/cljs Some of the problems that I reported above were due to inf-clojure only partially working for Clojurescript. Some things, like eldoc, were broken because they were written with nonportable Clojure code.

I also discovered that occasionally inf-clojure will detect the wrong REPL type, which results in some of the other problems I reported above. I filed a bug here: https://github.com/clojure-emacs/inf-clojure/issues/151


Sonny To

unread,
Jul 9, 2018, 5:42:26 PM7/9/18
to Clojure
Not sure what you mean by minimum but here's instruction on setting up a dev environment that works for me

my emacs init.el is at https://bit.ly/2z3gtyi
Reply all
Reply to author
Forward
0 new messages