<< Back to previous view

[NREPL-64] Add current ns to describe session's response Created: 24/Aug/14  Updated: 08/Sep/14

Status: Open
Project: tools.nrepl
Component/s: None
Affects Version/s: 0.2.4
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Bozhidar Batsov Assignee: Chas Emerick
Resolution: Unresolved Votes: 0
Labels: enhancement


In CIDER the REPL buffer gets created on receiving a describe-session response from the nREPL session that will back the REPL buffer. There's a problem with determining the default ns for the REPL buffer as many people use nREPL servers started with lein (lein repl :headless) and expect the `:init-ns` option for their project to the honored, but there's no easy way for clients to know what the default namespace is. It'd be great if this information was returned by `describe-session`.

Perhaps clients should be able to create a session with a particular default namespace to avoid the need for code like https://github.com/technomancy/leiningen/blob/554861505c23763d6583fe3b1f236a08ad02a4ca/src/leiningen/repl.clj#L103. I noticed that current the default ns is hardcoded as `user`.

Comment by Chas Emerick [ 25/Aug/14 8:59 PM ]

As you say, the default nREPL namespace is always user, so that's easy to know.

Leiningen's :init-ns support is implemented sanely AFAICT, given what it's aiming to accomplish. There's lots of vars in the session that one might want to customize on a per-project basis, and that tools might want to know the value of. I don't see any reason to special-case *ns*. This is one of the rare times where I'd say that a tool's best option is to use eval.

Comment by Bozhidar Batsov [ 27/Aug/14 10:09 AM ]

While I'd normally agree, the problem is that I'd have to rework cider's init in a bit awkward manner:

  • run describe session to obtain the REPL capabilities and version info
  • its callback should then do eval for ns
  • its callback should then spawn the REPL buffer

While I can certainly do this, chaining callbacks just to get some bootstrap info seems suboptimal to me. Ideally all bootstrap information
should be obtainable with a single request.
You can see the code in question here https://github.com/clojure-emacs/cider/blob/master/nrepl-client.el#L434

I can't imagine any other var value that a similar tool would like to know while bootstrapping. Obviously once you're up and running using eval is the natural solution.

Comment by Chas Emerick [ 05/Sep/14 8:05 AM ]

Not being thrilled with the idea of special-casing *ns*, I thought we might instead add a way for any middleware to contribute to the result of describe via a function in an optional descriptor slot. Each of them can be called here, and their results merged into the describe middleware's response. That function will need to take the requesting message (this will give the session middleware what it needs to provide *ns*, for example).

Happy to take a patch before I get around to this myself.

Comment by Bozhidar Batsov [ 05/Sep/14 8:25 AM ]

Sounds good to me. I guess the functions in question should be passed fully-qualified and have zero arity, right?

Comment by Chas Emerick [ 05/Sep/14 8:28 AM ]

I don't think they need to be named at all; e.g. session's :describe fn would just go here. They have to accept at least the request message as received/provided by the describe middleware.

Comment by Bozhidar Batsov [ 08/Sep/14 5:07 AM ]

Ah, I misinterpreted your previous comment. I thought you meant that we'd pass extra arguments to the describe request to get more things in the response. I think that now I understand the idea. I might take a stab at implementing this.

[NREPL-55] Support custom value rendering middleware Created: 13/May/14  Updated: 13/May/14

Status: Open
Project: tools.nrepl
Component/s: None
Affects Version/s: 0.2.3
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Gregory Look Assignee: Chas Emerick
Resolution: Unresolved Votes: 0
Labels: None


Currently, nREPL's interruptible-eval middleware hardcodes a dependency on pr-values. It would be nicer if the user could either specify alternate rendering middleware or if nREPL's built-in middleware accepted an arbitrary function to render values with. Specifically, this would enable pretty-printing REPL output.

I've set up a middleware to demonstrate this, in combination with the Puget printing library:

Currently it is possible to replace the default middleware, but it involves some ugly runtime metadata manipulation which reaches into the nREPL internals. Addressing this would be another step towards simplifying pretty-printing/color integration in the REPL.

[NREPL-54] No version of nrepl when connect to the lein-droid REPL Created: 04/May/14  Updated: 31/May/14

Status: Open
Project: tools.nrepl
Component/s: None
Affects Version/s: 0.2.3
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Eugene Apollonsky Assignee: Chas Emerick
Resolution: Unresolved Votes: 0
Labels: None



1. Connect Android device.
2. Start REPL.
lein droid run.
3. Forward port.
lein do droid forward-port, droid repl.
4. Send command {'op': 'describe', 'verbose?': 1}

'versions': { 'clojure': { 'incremental': 0, 'major': 1, 'minor': 6, 'qualifier': 'RC1'},
'nrepl': { }}}

Comment by Chas Emerick [ 05/May/14 11:51 AM ]

The current nREPL version is driven by reading the resource at /clojure/tools/nrepl/version.txt. If it's not found (perhaps because of an android packaging / classloader detail I'm not familiar with?), then no nREPL version will be returned.

FWIW, the version indicator is meant to be strictly advisory, and not really depended upon for e.g. exposing tooling capabilities. What are you needing the version indicator for?

Comment by Eugene Apollonsky [ 05/May/14 1:34 PM ]

Vim plugin "vim-fireplace" has nREPL version check (>0.2.0). OK, I think it can be fixed in the plugin.

Comment by Chas Emerick [ 05/May/14 3:29 PM ]

Yeah, that's likely there to guard against nREPL "classic" (which met its demise ~ 0.0.5). But, that's many years old at this point.

A more interesting question is: why isn't the version file being found by nREPL at load-time? I presume it's an Android-specific idiosyncrasy, but I'm curious nonetheless.

Comment by Eugene Apollonsky [ 31/May/14 4:39 PM ]

lein-droid developer commented this issue. It is Android-specific.

[NREPL-48] *1/*2/*3/*e nil in cloned session Created: 02/Jan/14  Updated: 02/Jan/14

Status: Open
Project: tools.nrepl
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Tim Pope Assignee: Chas Emerick
Resolution: Unresolved Votes: 0
Labels: None


Summary says it all. This isn't blocking me; just something I stumbled onto.

[NREPL-46] nREPL crashes when required more than one time with :reload-all Created: 21/Dec/13  Updated: 25/Aug/14

Status: Open
Project: tools.nrepl
Component/s: None
Affects Version/s: 0.2.2
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Alex Fowler Assignee: Chas Emerick
Resolution: Unresolved Votes: 1
Labels: bug

Irrelevant, but the provided test case project is for CounterClockWise on Eclipse. Although it should run just fine with vanilla lein.

Attachments: Zip Archive nrepl-test.zip    


When the namespace "clojure.tools.nrepl.server" is required more than once with :reload-all option, nREPL crashes. Accrding to current info it occures because some protocol instances get re-evaluated and are no longer the same JVM classes as they were before reload-all.

Steps to reproduce the bug in CCW:
1) Import the project into the workspace
2) Go into the core.clj
3) Click Clojure -> Load file in REPL
4) After the evaluation is complete, try evaluating (+ 1 2) in the repl. You should see no response at all.
5) Try writing something with letters, like "nrepl". The autocompletion will try and freeze and fail with the above exception.
6) Play around more to get a full hang or kill the REPL/Java to revive Eclipse.

Upon trying CCW autocompetion, the following exception occures, what might give some hint as to why:

Exception in thread "nREPL-worker-2" java.lang.IllegalArgumentException: No implementation of method: :send of protocol: #'clojure.tools.nrepl.transport/Transport found for class: clojure.tools.nrepl.middleware.pr_values$pr_values$fn$reify__1283
at clojure.core$_cache_protocol_fn.invoke(core_deftype.clj:541)
at clojure.tools.nrepl.transport$eval7291$fn_7292$G7280_7299.invoke(transport.clj:16)
at clojure.tools.nrepl.middleware.interruptible_eval$evaluate$fn_7726$fn_7739.invoke(interruptible_eval.clj:75)
at clojure.main$repl$fn__6597.invoke(main.clj:279)
at clojure.main$repl.doInvoke(main.clj:277)
at clojure.lang.RestFn.invoke(RestFn.java:1096)
at clojure.tools.nrepl.middleware.interruptible_eval$evaluate$fn__7726.invoke(interruptible_eval.clj:56)
at clojure.lang.AFn.applyToHelper(AFn.java:159)
at clojure.lang.AFn.applyTo(AFn.java:151)
at clojure.core$apply.invoke(core.clj:617)
at clojure.core$with_bindings_STAR_.doInvoke(core.clj:1788)
at clojure.lang.RestFn.invoke(RestFn.java:425)
at clojure.tools.nrepl.middleware.interruptible_eval$evaluate.invoke(interruptible_eval.clj:41)
at clojure.tools.nrepl.middleware.interruptible_eval$interruptible_eval$fn_1345$fn_1348.invoke(interruptible_eval.clj:171)
at clojure.core$comp$fn__4154.invoke(core.clj:2330)
at clojure.tools.nrepl.middleware.interruptible_eval$run_next$fn__7760.invoke(interruptible_eval.clj:138)
at clojure.lang.AFn.run(AFn.java:24)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)

Comment by Chas Emerick [ 19/Aug/14 8:56 PM ]

Confirmed. Using lein repl (though you're right that the particulars of the tooling shouldn't matter):

user=> 3
user=> (require '[clojure.tools.nrepl.server] :reload-all)
user=> 2

user=> 1

Not sure if it's the protocol or the types that are implicated (or both), but resolving this is going to be unpleasant.

Comment by Chas Emerick [ 19/Aug/14 8:57 PM ]

Couple of questions:

  • Does the fact that this occurs matter to anyone in a meaningful way?
  • Would an acceptable solution be that reloading of the affected namespaces be no-ops?
Comment by Alex Fowler [ 25/Aug/14 9:34 AM ]

Well, in my case I have a project which is required to often reload various namespaces because they are updated in the background. If it happens that any of the namespaces refer to nrepl, the thing crashes.

The error happens due to implementation problems and is not "a correct error" from the POV of Clojure language so it is better to be fixed. However, of course, in the real world it could be rather hard to do so..

Chas, could you please explain more about the no-ops approach? Do you mean it is possible to somehow force loading nrepl just once?

Comment by Chas Emerick [ 25/Aug/14 10:20 AM ]

Yes, there are ways to prevent the re-definition of types and protocols, but I'd like to avoid doing so. It's a hack, and would be an impediment to developing nREPL itself.

Actually, you should be able to accomplish the same thing more easily in your project: rather than require nREPL namespaces in the ns form, use a top-level require form, wrapped in a suitable conditional to determine if nREPL has been loaded yet:

(when-not (resolve 'clojure.tools.nrepl/version)
  (require 'clojure.tools.nrepl))

[NREPL-43] Document the availability/usage of *e, *1, *2, ... in nREPL Created: 04/Jul/13  Updated: 24/Aug/13

Status: Open
Project: tools.nrepl
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Enhancement Priority: Minor
Reporter: Jakub Holy Assignee: Chas Emerick
Resolution: Unresolved Votes: 0
Labels: documentation


I have only by chance discovered that nREPL binds the lat error/outputs to the vars *e, *1 etc. This should be documented clearly somewhere, possibly in https://github.com/clojure/tools.nrepl/blob/master/README.md

When I have forgotten the names of the vars while remembering that something like them exists, I tried to google them out but failed. So better documentation would help.

Thank you!

Comment by Chas Emerick [ 04/Jul/13 7:07 AM ]

The role of those vars is actually the same across all Clojure REPLs. In this department, nREPL is simply following Clojure's lead.

That said, yes, there is room to specify fully what nREPL's behaviour is, beyond the implied equivalence (at a minimum) to Clojure's included console REPL.

Comment by Jakub Holy [ 22/Jul/13 7:37 AM ]

Thank you for the clarification!

> The role of those vars is actually the same across all Clojure REPLs.

Do you know if this behavior of all Clojure REPLs is documented anywhere? And yes, it would be nice if the nREPL documentation linked to this doc and/or it printed a short summary and/or link when starting (in addition to the currently provided info about (source) etc.)


Comment by Chas Emerick [ 22/Jul/13 7:52 AM ]

REPL-bound vars are documented in a variety of places, though nowhere "official" AFAIK. We talked about it in Chapter 10 of Clojure Programming FWIW (I'm certain other books and online resources cover these vars as well, but the CP citation is the only one I have close at hand.)

FYI, the "currently-provided info" you mention is emitted by Leiningen/Reply, not nREPL.

Comment by Jakub Holy [ 24/Aug/13 4:50 AM ]

Thanks a lot, Chas, that was helpful. I have submitted a patch to Leiningen to include the info it its REPL' welcome message: https://github.com/technomancy/leiningen/pull/1310

Comment by Jakub Holy [ 24/Aug/13 5:38 AM ]

I have published a blog post about this, Clojure REPL stores the latest results in *1, *2, *3, exception in *e, to make it more googlable (is that even a word? ).

The top hit for "Clojure REPL" seems to be http://clojure.org/repl_and_main, so it perhaps should be documented there or it should link to a more detailed documentation. Not sure how to make that happen I have also checked http://clojure-doc.org/ but there doesn't seem to be a suitable place to add this info either. Perhaps it should be mentioned in the docstring of clojure.main/repl and the Clojure page should link to it?

Comment by Jakub Holy [ 24/Aug/13 5:52 AM ]

I have created an issue under Clojure itself, #CLJ-1247, so this can likely be closed.

[NREPL-36] Too many DynamicClassLoaders created Created: 10/Dec/12  Updated: 18/Apr/14

Status: Open
Project: tools.nrepl
Component/s: None
Affects Version/s: 0.2.0-RC1, 0.2.0-beta9, 0.2.0-beta10
Fix Version/s: None

Type: Defect Priority: Minor
Reporter: Colin Jones Assignee: Chas Emerick
Resolution: Unresolved Votes: 0
Labels: None


Not sure whether this ticket belongs here or in the Clojure-proper JIRA, so feel free to close if this is an inappropriate location. clojure.main/repl creates a new DynamicClassLoader on every execution, so it looks like the stack of classloaders grows without bounds. Seems a bit similar to http://dev.clojure.org/jira/browse/NREPL-31 in that clojure.main/repl has another assumption about when clojure.main/repl will run.

See https://groups.google.com/forum/?fromgroups=#!topic/clojure/firG9zTVecU%5B1-25%5D for the original report.

Comment by Chas Emerick [ 18/Apr/14 10:17 AM ]

Yes, this should be fixed upstream; a new DynamicClassLoader should only be set as the thread-context classloader if one is not already in place.

My first impulse upon seeing this was that this was "last straw" territory w.r.t. using clojure.main/repl (as recorded in the thread linked above), but the work necessary to stop depending upon it would be considerable (not because repl does much, but because interruptible-eval/evaluate is structured to cater to it). Some years on, and it's clear that this fundamentally a minor problem (insofar as hardly anyone has complained AFAIK), so a fix that requires e.g. Clojure 1.7.0 would be fine.

Generated at Wed Oct 01 23:44:01 CDT 2014 using JIRA 4.4#649-r158309.