-
Notifications
You must be signed in to change notification settings - Fork 51
Figwheel REPL plugin
Antonin Hildebrand edited this page Nov 2, 2015
·
8 revisions
With cljs-devtools installed, this allows you to:
- navigate native javascript values in devtools console
- drill down more complex cljs data structures interactively
- you want to run Figwheel REPL with rlwrap - this will give you history, bracket matching and other great enhancements
- it is handy to have REPL terminal available on a global keyboard shortcut - for example "Hotkey Window" in iTerm2
- Figwheel supports nREPL, so you can connect to its REPL remotely. I did this with IntelliJ and it worked like a charm. This way you can get additional sugary features from your IDE.
By default Figwheel REPL is silent on browser side. Luckily, thanks to Figwheel configurability, you are allowed to specify a custom REPL plugin. Let's implement a REPL plugin which will echo evaluated expressions entered in REPL into devtools javascript console (to be presented by cljs-devtools).
Here is an example implementation:
(ns your-project.figwheel
(:require [figwheel.client :as figwheel]))
(defonce ^:dynamic *inside-repl-plugin* false)
(defonce ^:const repl-marker-style "color:white; background-color:black; padding:0px 2px; border-radius:1px;")
(defn figwheel-repl-fix [code]
(.replace code
#"^\(function \(\)\{try\{return cljs\.core\.pr_str\.call"
"(function (){try{return cljs.core.identity.call"))
(defn intellij-repl-fix [code]
(.replace code
#"^try\{cljs\.core\.pr_str\.call"
"try{cljs.core.identity.call"))
(defn rewrite-repl-code-snippet [code]
(-> code figwheel-repl-fix intellij-repl-fix))
(defn eval [context code]
(js* "eval(~{code})"))
(defn present-repl-result [result]
(.log js/console "%cREPL" repl-marker-style result))
(defn eval-inside-repl-plugin [code]
(let [rewritten-code (rewrite-repl-code-snippet code)
result (eval rewritten-code)]
(present-repl-result result)
(pr-str result)))
(defn echoing-eval [code]
(if *inside-repl-plugin*
(eval-inside-repl-plugin code)
(eval code)))
(defn repl-plugin [& args]
(let [standard-impl (apply figwheel/repl-plugin args)]
(fn [& args]
(binding [*inside-repl-plugin* true]
(apply standard-impl args)))))
(defn start-figwheel []
(figwheel/start
{; your config goes here...
:eval-fn echoing-eval
:merge-plugins {:repl-plugin repl-plugin}}))
- we are hijacking evaluation by specifying our own
eval-fn
which does the echoing - echoing is achieved by rewriting incoming javascript code snippets
- code snippets are produced by REPL backends and may differ between nREPL implementations
- usually the expression is just wrapped in
pr-str
call so we unwrap it - here we provided unwrapping for Figwheel's implementation and IntelliJ's nREPL
- because
eval-fn
can be called by Figwheel in different situations than REPL evaluations, we have to implement arepl-plugin
which marks situations when eval-fn is being called from*inside-repl-plugin*
The above code is meant to be an example for you to implement your own version. It worked for me with Figwheel around this commit, but I believe it should be compatible with official 0.3.3 release as well. It is likely that this code will break in future. I have existing maintained implementation in the plastic project. Feel free to steal it.