Lots of utilities to work with Clojure Code. This package depends on Proto-REPL package, and a bunch of nREPL middlewares - refactor-nrep, proto-rep, and (in the future), cider-nrep.
Clojure-plus adds some extensions to Proto REPL - it adds lighttable-like watch expressions (with some limitations), beautiful stacktraces, goto-symbol in stacktraces, notifications on refresh (and syntax checking on it), and the possibility to control when, and how, to refresh.
It'll add coloring to the current S-Expression we're editing. We can style it editing the atom-text-editor::shadow .clojure-sexp .region
CSS selector, or we can just disable it.
Controlled by some parameters - refresh all cmd and refresh cmd defines which file contains the commands to refresh the current REPL. By default, uses files inside this plugin, which will just delegate to tools.namespace.repl/refresh
functions.
after and before refresh commands are bunch of commands that'll run before and after each refresh. By default, these commands just set clojure.test/*load-tests*
to false (before) and true (after) each refresh, so it'll not run Clojure or Midje tests. You can tune these parameters to stop an start servers. Clojure-Plus refresh will, too, update the state of each "watch expression" on Atom, so it's preferable to run this code in place of Proto REPL's.
Simple Refresh will just require the current namespace, with :reload
. This will not remove old vars, its syntax checking is not ideal, and it's particularly a bad idea overall. Use it only when you're working with strange code that doesn't supports at all tools.namespace
refreshes.
In Clojure Plus, we just treat watch expressions as a rewrite of code before sending it to REPL. This approach is fundamentally different from LightTable, when each watch is updated immediately when the code runs. In this package, we just rewrite the code before sending it to REPL, converting every mark to a println
and swap!
expression, then running it - and, after we run each watch, we aggregate the Clojure's Atom results and display then.
Clojure Plus adds a command - addWatcher
- that allows anyone to define new "watch" expressions. These may do anything you want - from displaying something on the console to anything you want (as far as it's rewritable). For instance, this would be able to define a global var in code for any seelection you want:
cljPlus = atom.packages.getActivePackage('clojure-plus').mainModulecljPlus.addWatcher('global', '(do (def global-var ..SEL..) global-var)')
This would rewrite the code, so if you have the code below, and you watch "x" value (in the second line), it'll rewrite it before sending it to REPL:
(fn [x y](+ x y)); Adding a watcher with the "global" we defined above; on "x" after the "+" will rewrite it as:(fn [x y](+ (do (def global-var x) global-var) y); Please, be aware that if you change the watch expression to the first; "x", in the function definition, you'll get a syntax error:(fn [(do (def global-var x) global-var) y](+ x y))
Unfortunately, watch expressions doesn't work correctly for macros like ->>
(it'll try to rewrite the macro code and will probably do the wrong thing).
Let's face it, Clojure stacktraces are awful. This package tries to ease this pain by providing inline stacktraces when something goes wrong - it'll try to parse Java stacktrace objects and provide it a better experience:
Please notice that it'll try to decompress and open files that are outside your project in the same way as goto-var (from Proto REPL) does. In the future, I'll try to parse stderr messages so that they display this same behavior, and probably we'll be able to parse then too and display then on editor (block decorations, maybe?).
Nothing is perfect, and this package is not an exception. There are still things that, somehow, doesn't work. A bunch of then is because the way Clojure works, and others are for other problems:
conj
) become something like conj-1211
when compiled, and Clojure doesn't get the change.Ideas for the project's future
fact
).
refactor-nrepl
for it, but it needs a lot of parameters and most of the time just gives me a Null Pointer Exception. Furthermore, it suffers from the same problem as the midje one, above.Good catch. Let us know what about this package looks wrong to you, and we'll investigate right away.