This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-03-30
Channels
- # aleph (2)
- # announcements (8)
- # babashka (12)
- # beginners (34)
- # calva (36)
- # cherry (3)
- # cider (1)
- # clj-kondo (11)
- # clj-otel (6)
- # cljdoc (31)
- # clojure (121)
- # clojure-conj (1)
- # clojure-czech (2)
- # clojure-europe (109)
- # clojure-nl (1)
- # clojure-norway (5)
- # clojure-uk (3)
- # cursive (3)
- # datahike (1)
- # datomic (9)
- # deps-new (6)
- # docker (5)
- # emacs (21)
- # fulcro (4)
- # hoplon (16)
- # introduce-yourself (2)
- # london-clojurians (5)
- # lsp (87)
- # malli (17)
- # missionary (1)
- # nbb (27)
- # off-topic (257)
- # pathom (4)
- # portal (42)
- # practicalli (1)
- # rdf (3)
- # releases (2)
- # shadow-cljs (49)
- # slack-help (3)
- # timbre (2)
Is there a way to pin something in portal?
When debugging I often use def
within code and itβs easy to evaluate it for the last value that was defined.
This is better than logging or printing for cases where that code may be executed repeatedly and spamming my logs.
Is this something that could be achieved with portal? Maybe even with changes?
Is the idea to use the value at the repl later or that you want to visually compare it to another?
You can pull a selected value back into the repl via derefing the portal atom which is returned from portal.api/open
(ns user
(:require [portal.api :as p]))
(def values (atom []))
(defn push [& args]
(swap! values into args))
(p/register! #'push)
βοΈ would allow you to collect as many values as you want over time. Just select the value or multiple values and call your custom command user/push via the command paletteI have tried to write some fairly fancy code to ensure that the most recently tap>
'd value always ends up as the most recent value in Portal with any middleware tap>
'd values below it, so that I can programmatically get at that value from my editor.
I don't want to have to interact with the Portal UI in general to select anything. I want to drive it all from my editor. And that requires a degree of predictability of where values are in the UI in order to get at them programmatically. I pretty much never want to interact with some arbitrary result produced by evaluation middleware -- but I want to drive Portal's UI from my editor to cause interactions with the most recent interesting value.
In many ways, it would be ideal for me to have middleware eval output go into a separate panel in Portal and have just my direct tap>
values go into the regular panel so the most recent was always what I explicitly tap>
'd.
I want the Portal UI to be more "drivable" by code, overall :)
TL;DR: it's not so much about having a specific value in Portal accessible to the program, as having the program be able to drive the UI in Portal around a specific value.
For example, I commonly want to cycle through viewers programmatically for the "most recently tap>
'd value" but I want to ignore any middleware-produced data for that. Seeing that output is useful, and having the option to switch to the Portal UI and interact with it is nice -- and sometimes necessary -- but not my primary workflow when debugging.
I have logging wired up to tap>
into Portal, for example, and I already have a hot key set up to toggle that wiring on and off so I can eval a specific piece of code and not have logging clutter up Portal's UI, even tho' in general logging is useful. And I may end up doing something similar for middleware output, but it's still a pain to have to do this manually around specific evaluations.
Having two separate sections in the UI for this would be my ideal choice: and then I could have logging and middleware go to the "secondary" panel and my explicit tap>
results go to the "primary" panel -- and then programmatically interact with just that primary panel.
Being able to start multiple VS Code launcher/viewer instances from a single JVM might solve this too -- not sure if that's possible?
@U04V70XH6 would something like the following fit your workflow better?
(def tap-list (atom (list)))
(def eval-list (atom (list)))
(defn submit [value]
(if (:portal.nrepl/eval value)
(swap! eval-list conj value)
(swap! tap-list conj value)))
(add-tap submit)
(portal.api/open
{:window-title "tap-list"
:value tap-list})
(portal.api/open
{:window-title "eval-list"
:value eval-list})
Can I have two VS Code windows open?
That's cool... let me try that...
The tap-list that is loaded into portal by default is:
(defonce ^:private tap-list
(atom (with-meta (list)
{:portal.viewer/default :portal.viewer/inspector})))
My setup is somewhat complicated by having my Portal start code be part of my Calva custom REPL snippets with logging wired up elsewhere but let me spend an hour playing with this... I had no idea I could manage my own tap list like that...
What will the portal.api/*
functions do when there are multiple instances?
I think they do a broadcast, they should have an arity which includes passing in a specific instance
Well, I have a lot of this sort of stuff:
{:name "Portal Viewer"
:key "0"
:snippet (portal.api/eval-str
(str
'(let [state portal.ui.state/state]
(-> (portal.ui.commands/select-none state)
(.then #(portal.ui.commands/select-child state))
(.then #(portal.ui.commands/select-child state))
(.then #(portal.ui.commands/select-next-viewer state))
(.then #(portal.ui.commands/select-none state))))))}
Ah, it accepts portal
too... OK, this is looking very promising π
Ohh, also I added {:await true} to eval-str so you can block on promises if you still wanted to use something like that
Nice, thanks.
OMG! THIS IS SO AWESOME!! This dramatically simplifies my Portal setup and provides so much more value!!!
Interesting tap>
'd values on top; middleware output below:
That's looking very nice π I think we have portal setup similarly for logging / taps at work
https://cljdoc.org/d/djblue/portal/0.37.1/doc/guides/custom-tap-list for some other ideas
The "danger" of an infinitely flexible toolchain is that you can almost never know what is possible π
I think the upcoming notebook updates are gonna make things even more flexible / fun for vscode users
https://github.com/seancorfield/vscode-calva-setup/commit/d379e6b202dc44404a82d3eb44ee8ab8d9bbd025 -- so much simplification π
Ohh, if your eval-str commands return :portal.api/ignore
the nrepl middleware will not tap them π
Good to know about :portal.api/ignore
(allow that seems a strange value for the nREPL middleware to care about -- I'm surprised it isn't :portal.nrepl/ignore
π )
That would be better, but I have some custom socket repl based tooling that I use that needs the same behavior so I use that keyword for both
I updated my config.edn to use that. It caught another case I wasn't handling, so that's helpful.
For folks using my https://github.com/seancorfield/vscode-calva-setup repo -- or interested in a "real-world" VS Code/Calva/Portal setup -- I've updated the custom REPL snippets (which drive Portal in my setup) to run two Portal windows in VS Code: one for middleware output (which looks mostly like logging) and one for dedicated tap>
output, such as when you're debugging code or doing explicit ctrl+alt+t space
tap>
evals on code, so that you can view and interact with them separately: my custom REPL snippets (`ctrl+alt+space <key>`) all operate on the dedicated tap>
output window, and you can "lift" the most recent middleware result into the tap>
window (`ctrl+alt+space l`).
In addition, if you're using my https://github.com/seancorfield/dot-clojure repo and the :dev/repl
alias there, logging from clojure.tools.logging
is also routed into the middleware output window now, rather than the main tap>
window.
I want to reiterate my gratitude for all the work @djblue puts in on Portal and for creating such an amazingly flexible and powerful tool!
It's really exciting seeing the evolution of how you utilize Portal in your workflow so thanks for taking the time to share your experiences β€οΈ
I need to write another blog entry π