cider icon indicating copy to clipboard operation
cider copied to clipboard

Add optional tap> output to the inspector

Open bsless opened this issue 4 years ago • 10 comments

Hello, Seems like tap> and the inspector can work very well together, and adding such capability takes only a few lines of code. I propose a new interactive function cider-inspect-tap which will display an atom updated by a tap added by cider.

In the Clojure side, this is all the needed implementation:

(defn queue
  [& args]
  (into (clojure.lang.PersistentQueue/EMPTY) args))

(defn bounded-conj
  [^long n coll x]
  (let [b (== (count coll) n)]
    (cond-> (conj coll x)
      b pop)))

(def queue-size (atom 16))
(def taps-queue (atom (queue)))

(defn set-size! [n] (reset! queue-size n))

(defn reset-queue! [] (reset! taps-queue (queue)))

(defn qtap! [x] (swap! taps-queue #(bounded-conj @queue-size % x)))

(defn register! [] (add-tap qtap!))

(defn deregister! [] (remove-tap qtap!))

(defn view! [] (reverse (deref taps-queue)))

In CIDER, a minimal implementation would be

;;;###autoload
(defun cider-inspect-tap ()
  "View taps queue."
  (interactive)
  (cider-inspect-expr "(view!)" (cider-current-ns)))

I would happily PR this, but I wanted to start by opening an issue to track discussion instead of having it on Slack, and to ask a few questions regarding design.

  • Should Clojure code be added to orchad, cider-nrepl, or just injected via CIDER?
  • Should the code be in the same name space and package as the inspector or on its own?
  • How should older versions of Clojure with no tap> support be handled?
  • Should the inspected expression be defined in elisp as a var? const? Should I use requiring-resolve?

These are the most important questions as far as I can see for now.

Let me know what you think and I'll happily start on an implementation.

Cheers

bsless avatar Sep 18 '21 09:09 bsless

Should Clojure code be added to orchad, cider-nrepl, or just injected via CIDER?

The Clojure part of the inspector lives in Orchard, so it should be updated there.

Should the code be in the same name space and package as the inspector or on its own?

Same ns is fine.

How should older versions of Clojure with no tap> support be handled?

Probably this should be some no op there. I think we support only Clojure 1.8+. When was it added?

Should the inspected expression be defined in elisp as a var? const? Should I use requiring-resolve?

I don't quite get the question. More details please.

Sorry for the slow response. I've been traveling a bit lately and I've spent little time in front of a computer. @alexander-yakushev might have something to say about this as well, given he's been working the most on improving the inspector.

bbatsov avatar Oct 02 '21 12:10 bbatsov

I don't mind the slow response, maintainers have a life, too To clarify what I meant with my last question, when I call cider-inspect-expr, should that expression be a hard coded string? defined with defvar or defconst? Should it be a fully qualified name, i.e. some.ns/view! or just view!? Should the code I send to inspect be wrapped with requiring-resolve or can I assume it will be loaded?

bsless avatar Oct 03 '21 07:10 bsless

To clarify what I meant with my last question, when I call cider-inspect-expr, should that expression be a hard coded string?

I'd go with a defvar.

Should it be a fully qualified name, i.e. some.ns/view! or just view!?

Fully-qualified names work best.

Should the code I send to inspect be wrapped with requiring-resolve or can I assume it will be loaded?

Well, that depends. I just realized that you're thinking of evaluating the code directly, but so far there's no place where CIDER just evals some code that lives in say cider-nrepl. Might be prudent to wrap this in some nREPL op, which would also solve all the other points you mentioned (it will just call that view! function you proposed).

bbatsov avatar Oct 27 '21 06:10 bbatsov

Would it be possible to have cider watch the var, and automatically display changes in the inspector?

For that to work well, the inspector would probably need to keep, and allow navigation through, history. Presumably it could keep history using weak references.

hugoduncan avatar Dec 07 '21 17:12 hugoduncan

To not override the default inspector's behavior, to always display the last evaluation result, I think a good way to go about it would be adding a *cider-tap-inspector*

bsless avatar Dec 07 '21 18:12 bsless

Something like this would be fine by me.

bbatsov avatar Dec 31 '21 10:12 bbatsov

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contribution and understanding!

stale[bot] avatar Apr 17 '22 00:04 stale[bot]

up

darkleaf avatar Apr 17 '22 13:04 darkleaf

@bsless your code works great as-is.

Would you like to create a PR?

If not, I can productionize it :)

If you have since added new tweaks, please edit your OP reflecting them.

Cheers - V


Edit: I crowdsourced extra design/impl considerations here https://clojurians.slack.com/archives/C03S1KBA2/p1695754708326079

vemv avatar Sep 26 '23 18:09 vemv

I just integrated this solution over the weekend, and it works great! Thank you very much!

I can hardly wait to see this in CIDER! 🎉

raszi avatar Jan 22 '24 10:01 raszi