Tuesday, February 8, 2011

rlwrap: enable Clojure readline support

In my last post I somewhat ended up complaining that the system wide clojure I like to use (and I explaine why and when) basically lacks readline support. In Clojure that is mostly supported through JLine and the brew recipe does not install JLine (which is fine).

Adding clojure-contrib support is easy: we have just to install the library (brew install clojure-contrib and then add it to CLASSPATH). Basically I added in my .zshenv

export CLASSPATH=$CLASSPATH:/usr/local/Cellar/clojure-contrib/1.2.0/clojure-contrib.jar

Ok... now the time for readline support. My first temptation was adding a brew recipe for JLine. Then I had to modify clojure recipe. I bet it was not hard. As far as I know, it is just a matter of editing the following method in the recipe (brew edit clojure):

def script
<<-EOS
#!/bin/sh
# Runs clojure.
# With no arguments, runs Clojure's REPL.

# resolve links - $0 may be a softlink
CLOJURE=$CLASSPATH:$(brew --cellar)/#{name}/#{version}/#{jar}

java -cp $CLOJURE clojure.main "$@"
EOS
  end




This is extremely easy and interesting, indeed. I'm considering editing it in order to add a dependency to clojure-contrib and directly add it to the classpath. However, I did something different before opening the recipe: I read the sources of the lein script.

As I pointed out, lein repl has some readline support, but does not install as a dependency JLine. So I opened the /usr/local/bin/lein script and read it. And I discovered the wonderful tool called rlwrap. It essentially adds readline support to applications without it. In fact lein can both use rlwrap and JLine and as far as I can tell rlwrap support seems slightly superior.

So I just installed (brew install rlwrap) and now I can just run

% rlwrap clj

to obtain the desired effect.

Opening the full clojure recipe, I found out that there is another possibility; they say in the caveats section that:

  def caveats; <<-EOS.undent<br />    If you `brew install repl` then you may find this wrapper script from<br />    MacPorts useful:<br />      http://trac.macports.org/browser/trunk/dports/lang/clojure/files/clj-rlwrap.sh?format=txt<br />    EOS<br />  end


I probably did nor pay enough attention to installation messages!
However, it appears that repl is able to work with rlwrap but does not provide readline support on its own:

"""If you have rlwrap(1) installed you'll automatically get the full benefits of readline: history, reverse searches, etc."""

For me rlwrap clj works correctly.

, ,

2 comments:

Anonymous said...

For proper clojure support with rlwrap, you need to add --quote-characters='"' (which causes rlwrap to stop treating single quote as a paired quote character). Adding --command clojure will make rlwrap keep command history between sessions.

You can also get rlwrap to autocomplete clojure function names, but that's a bit more complicated.

Unknown said...

Yes. You have a good point. I did not stumble into this, as I did not try to insert a symbol. Seems that my clojure is far different from my lisp.