Fork me on GitHub
#portal
<
2022-03-21
>
Carlo19:03:24

New questions. My workflow is amazing in the JVM since when I started using functions like:

(defun portal.ui.commands/select-next ()
  (interactive)
  (portal/invoke-portal-command
   "(portal.ui.commands/select-next portal.ui.state/state)"))
but these don't work when I open portal from a cljs repl. Is there any known reason for this @djblue?

djblue19:03:03

If for the cljs repl, you are using portal.web, you may need to conditionally swap out portal.api/eval-str to portal.web/eval-strin your command via a reader condition šŸ‘Œ

djblue19:03:40

If for the cljs repl, you are using the remote api and sending taps to a remote instance of portal hosted via the jvm, the commands would need to be executed against a jvm repl.

Carlo19:03:34

So, I'm using portal.web, but where did I use portal.api/eval-str in my command?

djblue19:03:23

My assumption is that portal/invoke-portal-command is wrapping the string

Carlo19:03:39

yes that was indeed the case, and I messed up my emacs file, so I wasn't seeing it šŸ˜‚. The other question was: usually I start portal from a user.clj file, but here if I try to use it from a user.cljs file, which is not imported by the main file of my project, the repl will say:

Execution error (ReferenceError) at (<cljs repl>:1).
user is not defined
what's the correct way of using a user.cljs namespace?

djblue19:03:12

I think the user ns for cljs is cljs.user

Carlo19:03:47

it's possible that's shadow.user, by reading the shadow docs, but do people just use that?

Carlo19:03:03

(defun portal/invoke-portal-command (command-str)
  (cider-nrepl-sync-request:eval
   (concat "(#?(:clj portal.api/eval-str :cljs portal.web/eval-str) \"" command-str "\")")))

Carlo19:03:45

this works, thank you šŸ˜

ā¤ļø 1
djblue19:03:56

That is very nice! I need to add this to the docs šŸ‘Œ

Carlo19:03:56

I can paste all of my related config if you want (might be useful to emacs users)

djblue19:03:50

I would be curious what the emacs integration side looks like šŸ’Æ

Carlo19:03:14

This is for doom emacs, but the core functions should be usable anywhere.

šŸ™ 2
šŸ†’ 1
clojure-spin 2
Carlo19:03:47

fixed the clear function too

šŸ’Æ 1
teodorlu21:03:49

Wait. Are you controlling portal - outside of Emacs - with a hydra - inside Emacs? I have to try this.

Carlo09:03:46

yes, that's the purpose of all this line of thinking. It started because I couldn't control the shortcuts, but then I understood the brilliant design decision of accepting UI commands from an external source

teodorlu11:03:45

šŸ’Æā¤ļø

nmkip18:03:12

Very nice! Thanks! I had super simple setup an advice function to tap the things I evaluated. This is much better! Do you have to click on any element before using the hydra for it to start working? Mine isn't working until I click an element inside portal, then r,h,j,l,k start working.

Carlo09:03:00

@UJCC6CE9E No I don't need to click anything, basically the function select-root is used to select the top level element in case nothing is selected (and then I can use h,j,l,k)

nmkip10:03:35

@UA7E6DU04 Yes, thanks! Yesterday I got it working, I think that maybe I had an older version of portal because I didn't see the select-root function in the command palette. Btw, have you tried calling copy | copy-path | copy-json from emacs?

Carlo10:03:19

Oh yes, that's it, select root was added very recently! Unfortunately I never had a compelling use case that forced me to set up copy | copy-path | copy-json for now, how are you using them?

nmkip10:03:41

I sometimes use copy with data that comes from a db/http request or even from taps that I've added. I havent had use cases for the other 2. Calling

(portal/invoke-portal-command
   "(portal.ui.commands/copy portal.ui.state/state)")
isn't working for me . I'm trying to figure out why.

djblue17:03:01

Might be a clipboard permission issue or because copy is returning a #object[HTMLTextAreaElement [object HTMLTextAreaElement]] :thinking_face:. Try wrapping it in a (do ... nil) and see if that works.

nmkip11:03:41

no šŸ˜ž

Carlo16:04:26

@djblue what should be wrapped in a (do ... nil) ?

(portal.web/eval-str
   "(do (portal.ui.commands/copy portal.ui.state/state) nil)")
this returns nil but nothing gets put in the clipboard

djblue16:04:04

Does the browser console complain about permissions?

djblue16:04:55

The code above works for me in chrome :thinking_face:

Carlo16:04:49

I can get:

(portal.web/eval-str
   "(.-value (portal.ui.commands/copy portal.ui.state/state))")
to show me the text value, but not to copy it to the clipboard

Carlo16:04:04

I don't see any error related to clipboard permissions

djblue16:04:50

Quick question, do you have a value selected in the UI?

Carlo16:04:23

yes, I do when I try the command

djblue16:04:31

Dang, not sure what's up then. Works perfectly for me.

Carlo16:04:36

ok, now I explicitly granted clipboard permissions to localhost:3000 and that didn't seems to change anything

Carlo16:04:46

@UJCC6CE9E is this working for you?

Carlo16:04:53

@djblue are you using the dev version?

djblue16:04:04

I tried both just in case and they both worked šŸ‘Œ

Carlo16:04:21

are you on linux? (I'm on linux using chromium)

nmkip16:04:33

No, it didn't work for me.

djblue16:04:41

ohh, that might be it. I'm on OSX

nmkip16:04:46

I'm also on linux.

djblue16:04:06

Does copy work from the command palette?

Carlo16:04:46

doesn't that lack something like:

navigator.clipboard.writeText(copyText.value);
https://www.w3schools.com/howto/howto_js_copy_clipboard.asp

Carlo16:04:17

This doesn't copy anything for me:

(let [el (js/document.createElement "textarea")]
    (set! (.-value el) "Hey there")
    (js/document.body.appendChild el)
    (.select el)
    )

djblue16:04:00

(js/document.execCommand "copy") is the key I think

Carlo16:04:25

oh I had to expand the preview, sorry facepalm

Carlo16:04:15

still, it doesn't copy anything in the clipboard

djblue16:04:30

No worries, this method of copying might be outdated and we could switch to a modern approach

djblue17:04:13

Mind switching to navigator.clipboard.writeText(copyText.value); and see if that works in linux?

Carlo17:04:33

I'm trying at the repl:

ā¤ļø 1
Carlo17:04:43

(let [el (js/document.createElement "textarea")]
    (set! (.-value el) "Buongiorno signore")
    (js/document.body.appendChild el)
    (.select el)
    (.-value el)
    (js/Promise.resolve (.writeText (.-clipboard js/navigator) "HEEEEY")))

Carlo17:04:58

trying to get the right invocation for the navigator part

Carlo17:04:15

the problem with the clipboard API anyway is that:

Don't try the above code in the console. To use the Clipboard API, the document needs to be in a focused state. Otherwise, a DOMException will be thrown.

šŸ˜­ 1
Carlo17:04:45

thinking generally though, this just means that maybe I shouldn't try to call that command from emacs. Instead I could just select the bit I'm interested in, and arrange emacs to insert @p in the buffer

Carlo17:04:27

or arrange emacs to put it in the clipboard šŸ˜‚

djblue17:04:38

Does (js/document.execCommand "copy" false) make any difference?

djblue17:04:15

Or with true as well :thinking_face:

Carlo17:04:33

no, no difference with both

djblue17:04:51

ok, thanks for trying šŸ™

šŸ™Œ 1
djblue19:03:06

This is awesome, thanks for sharing! I'm going to need to set this up for myself.

Carlo19:03:47

it's a pleasure, thank you for answering all my questions! Btw I just fixed the definition of the clear function

šŸ‘ 1
Carlo20:03:34

the only thing that I still feel could have a bit more support from the portal side, is having nice commands to change the viewers of the data (my code isn't yet working properly for that my code works but I would prefer if it was cleaner šŸ˜‚)

Carlo21:03:17

I'm also curious about why this approach doesn't work, when I call the function from the portal ui

(defn add-pprint-viewer-meta [thing]
  (with-meta thing {:portal.viewer/default :portal.viewer/pprint}))

(p/register! #'add-pprint-viewer-meta)

djblue22:03:46

I think it has to do with how portal is capturing runtime objects. Portal is only checking value equality, not metadata. Since the UI has already received this value, the UI receives the ID of the previous value with the old metadata.

Carlo22:03:10

hmm I see. Do we have a way of setting new predicates from the user side? Like, if you have data of this form [[{:a :b}]] I feel having to traverse two layers of vector is rarely the first choice I'd make

djblue22:03:15

I've been thinking about adding a user defined way to specify a function which can pick a default viewer

djblue22:03:32

Is that kinda what you are thinking? If so, what expectations would you have?

Carlo22:03:53

yes, that's the kind of think I have in mind. The expectation I would have is being able to easily "patch" the default behavior; so, if none of viewers apply, I fall back to the viewers as they are now

Carlo22:03:12

also, I'd like to know how to write more complex visualizers; for example, I'd love to write a visualizer for music or for the custom objects in my code

djblue22:03:30

For custom viewers, there are a few options: ā€¢ hiccup + existing viewers - only allows composition of existing viewers, no new behavior ā€¢ vega / vega-lite - pretty extensive data dsl for viz ā€¢ full reagent component registered via portal.ui.api/register-viewer! and code loading is handled via eval-str , however no direct support for npm libs

Carlo23:03:41

So, regarding equality. If I evaluate (list 1 2 3) and then [1 2 3] the second result will be displayed as (1 2 3) probably because it's already cached and (= (1 2 3) [1 2 3]), but I think it's an extremely confusing effect

Carlo23:03:47

and it's a bit unclear for me why we would need caching in the first place. Is it to keep the visualizations in sync?

djblue23:03:14

Ohh, that's a good point, can probably fix in a similar way as with metadata. The caching is for performance because the backend/frontend are very chatty, but tend to send the same values around a lot.