A companion library to scope-capture, providing an nREPL middleware that lets you put your REPL in the context of an Execution Point (via sc.api/letsc
).
Project status: alpha quality. Tested empirically on Cursive. OTOH, this is typically only used in development, and for most purposes you can just falling back to using the raw API of scope-capture.
NOTE: this middleware is only suitable for programs where the REPL and the nREPL middleware run in the same process (typically JVM Clojure, typically not JVM-compiled ClojureScript.)
This library exposes an nREPL middleware in the Var sc.nrepl.middleware/wrap-letsc
.
It works with both the nREPL library and the older tools.nrepl: you must provide these dependencies separately.
You need to declare dependencies both to this library and to nREPL itself. You'll typically want to put them in a custom profile, as recommended by the nREPL documentation:
;; in your deps.edn file:
{
;; [...]
:aliases
{
;; [...]
:nREPL
{:extra-deps
{nrepl/nrepl {:mvn/version "0.5.3"}
vvvvalvalval/scope-capture-nrepl {:mvn/version "0.3.1"}}}}}
Add the following to your project.clj file (potentially in a development profile):
:dependencies
[... ;; you probably have other dependencies
[vvvvalvalval/scope-capture-nrepl "0.3.1"]]
:repl-options
{:nrepl-middleware
[... ;; you may have other nREPL middleware
sc.nrepl.middleware/wrap-letsc]}
Assume you placed a sc.api/spy
(or sc.api/brk
) call in the following code:
(defn foo
[x y]
(let [z (* x y)]
(sc.api/spy
(+ (* x x) (* 2 z) (* y y)))))
;SPY <-3> /home/me/myapp/src/myapp/myns.clj:4
; At Code Site -3, will save scope with locals [x y z]
You ran it and got an Execution Point with id 7
:
(foo 2 23)
;SPY [7 -3] /home/me/myapp/src/myapp/myns.clj:4
; At Execution Point 7 of Code Site -3, saved scope with locals [x y z]
;SPY [7 -3] /home/me/myapp/src/myapp/myns.clj:4
;(+ (* x x) (* 2 z) (* y y))
;=>
;625
You can now 'place yourself' in the context of that Execution Point by calling sc.nrepl.repl/in-ep
(sc.nrepl.repl/in-ep 7)
Once you've done that, you'll see that the locals bindings of the Execution Point are always in scope, although not via Global Vars:
x
=> 2
y
=> 23
z
=> 26
(+ x z)
=> 28
This is achieved by wrapping each code expression to evaluate (via the 'eval' and 'load-file' nREPL ops) with (sc.api/letsc <<ep-id>> <<expr>>)
.
So the semantics are exactly those of sc.api/letsc
, you just don't get the tedium of writing them manually.
Once you're done with that Execution Point, you put your REPL back in a normal state by using sc.nrepl.repl/exit
:
(sc.nrepl.repl/exit)
Copyright © 2017 Valentin Waeselynck and contributors.
Distributed under the MIT License.