vvvvalvalval / scope-capture

Project your Clojure(Script) REPL into the same context as your code when it ran
MIT License
576 stars 14 forks source link

Request: alias for "most recent ID" #34

Closed yuhan0 closed 4 years ago

yuhan0 commented 5 years ago

I just started using this library and it seems to be a really nice lightweight alternative to debuggers :)

However a majority of the time during development, I am incrementally redefining functions and calling them with different arguments, and would only be concerned with inspecting the most recently captured result.

A major source of friction in this REPL driven workflow comes when each function evaluation triggers a new scope capture ID, which means having to manually scroll up the (potentially very large) REPL output to find the line that says eg. SPY [427 -20], take note of the number 427, and go around updating all the IDs in defsc/letsc forms. In a few incidents so far, I entered the wrong ID or forgot to update it, leading to confusion when the captured values seemed to not match up with reality.

(defn foo [x]
  (sc.apy/spy
   (let [var ...]
     ...)
   ))

(foo "abc") ; <- call foo, capturing the scope of var within

(letsc 427 ; <-- this number has to be updated after each function call
  (some-analysis-involving var))

Am I missing some other way of reducing this hassle needed? Ideally I should be able to go back and forth seamlessly between editing a function body, testing it with different arguments and immediately being able to investigate its scope if something behaves unexpectedly.

It would be great if there was an alias to refer to the most recently evaluated ID, much like the *1 variable in the Clojure repl.
The number 0 seems to be a good candidate, since (as far as I can tell) it doesn't have a currently assigned meaning.

(letsc 0 ; <-- refers to the most recent evaluated call to foo
  (some-analysis-involving
   var))

Alternatively one could enter a negative number referring to the capture location (-20 in this example), which would be overloaded to mean "most recent/ maximum capture ID at that particular capture site"

vvvvalvalval commented 5 years ago

Thanks @yuhan0, thanks for your kind words scope-capture!

Are you aware of the sc.api/last-ep-id function? It won't give you exactly what you suggested, i.e a shorthand macro using the last EP id, which is not possible if we want to preserve ClojureScript compatibility (the defsc/letsc macros don't have access to information about the Execution Points, only about the Code Sites.)

So that makes it easier to retrieve the last EP id, which may well be good enough for you. Also note that you can use a sub-repl with scope-capture, either via sc.repl/ep-repl or using the scope-capture-nrepl library, in which case you can get what you want by evaluating always the same expression, e.g (sc.repl/ep-repl (sc.api/last-ep-id)) - it's easy enough to make an editor shortcut for that.

Please tell me if that works for you.

yuhan0 commented 5 years ago

Thanks for the reply! I only just got around to trying out your suggestions - the last-ep-id function was exactly what I was looking for :) I had actually briefly grepped through the source trying to find references to "recent" IDs and didn't think of the keyword "last". Strange to see that it wasn't documented anywhere, as a newcomer I wouldn't know what an EP or CS was, so it's unlikely one would discover such useful functionality.

Anyway, I ended up defining these shorthand macros:

(defmacro letsc*
  "Like letsc, but uses the last (most recently evaluated) EP id."
  [& body]
  `(letsc ~(sc.api/last-ep-id) ~@body))

(defmacro defsc*
  "Like defsc, but uses the last (most recently evaluated) EP id."
  []
  `(defsc ~(sc.api/last-ep-id)))

which worked exactly as I wished!

(defn hello [x]
  (let [y (apply str (reverse x))]
    (spy (str "Hello, " y))))

(hello "dlrow")

(letsc* y)
;; => "world"

(I don't use Clojurescript at all so I'm not sure if they would be compatible there)

vvvvalvalval commented 4 years ago

Mentioned the relevant techniques in the Tips and Tricks doc page.