obb

zane 2022-01-03T02:34:10.000200Z

@zane has joined the channel

zane 2022-01-03T03:01:14.000300Z

set the channel description: Ad-hoc ClojureScript scripting of Mac applications via Apple’s Open Scripting Architecture. https://github.com/babashka/obb

borkdude 2022-01-03T03:01:19.000500Z

@borkdude has joined the channel

james 2022-01-03T08:48:35.000700Z

@james427 has joined the channel

borkdude 2022-01-03T08:49:17.000800Z

borkdude 2022-01-03T08:49:37.000900Z

simongray 2022-01-03T08:58:03.001100Z

@simongray has joined the channel

simongray 2022-01-03T08:59:59.001300Z

Do anyone happen to know where Apple documents their own “standard library”? I.e. what is the MDN for Apple’s JS.

simongray 2022-01-03T09:00:49.001700Z

I guess this link in the README is the closest thing? https://developer.apple.com/library/archive/documentation/LanguagesUtilities/Conceptual/MacAutomationScriptingGuide/

zane 2022-01-03T09:11:01.002100Z

zane 2022-01-03T09:12:22.002200Z

zane 2022-01-03T09:13:31.002800Z

The scripting guide you linked is great too.

zane 2022-01-03T09:15:10.004200Z

You have access to Cocoa through JXA, so you can even create full-on applications if you want. But if you were to go down that path it might be worthwhile to just compile to JavaScript instead of running everything through obb.

simongray 2022-01-03T09:16:05.004500Z

Right.

simongray 2022-01-03T09:16:40.005400Z

I was thinking of creating an Input Method using Apple’s JS, so I might use this to get my feet wet

zane 2022-01-03T09:16:47.005600Z

I also want to stress that this thing is in no way ready for prime time. There’ll be (lots of) bugs.

simongray 2022-01-03T09:16:56.005900Z

sure, it’s just fun, I get that 🙂

👍🏻 1
borkdude 2022-01-03T09:27:42.006500Z

@zane I recommend putting these links in the README

borkdude 2022-01-03T09:28:01.006900Z

@zane I also recommend watching the repo https://github.com/babashka/obb/watchers for issues :)

borkdude 2022-01-03T09:28:25.007400Z

I created a couple of issues around the logistics of the project

zane 2022-01-03T09:29:26.008200Z

Sounds good!

zane 2022-01-03T09:31:35.008400Z

@borkdude All these suggestions sound great. Will get to them as I’m able.

borkdude 2022-01-03T09:32:39.008600Z

Cool, no hurry! :)

borkdude 2022-01-03T09:47:14.009Z

@zane Is this something specific to #obb or something that is relevant to SCI as well? https://github.com/babashka/obb/commit/ae9783c3ded24d7eca109a8cdbc608011ed62c10

zane 2022-01-03T09:47:52.009200Z

@borkdude I wanted to discuss that with you, actually. Those changes might belong upstream.

borkdude 2022-01-03T09:48:03.009400Z

👍

zane 2022-01-03T09:48:52.009600Z

This is handling a situation where you have a callable that for some reason isn’t an instance of Function &/or doesn’t have .apply.

zane 2022-01-03T09:49:09.009800Z

I’m not sure how common that is outside of JXA.

zane 2022-01-03T09:29:10.008100Z

@borkdude Yeah, I’m definitely going to add a lot more documentation. I wasn’t expecting eyes on the repository this quick. 😅

Søren Sjørup 2022-01-03T09:45:38.008900Z

@soren has joined the channel

borkdude 2022-01-03T09:51:29.010Z

set the channel topic: https://github.com/babashka/obb

borkdude 2022-01-03T09:54:51.010200Z

Another nice example for the README:

borkdude 2022-01-03T09:55:19.010500Z

$ obb -e '(-> (js/Application "Google Chrome") (.-windows) (aget 0) (.activeTab) (.title))'
Slack | obb | clojurians

🙌 1
🙌🏻 1
borkdude 2022-01-03T09:59:26.010900Z

Added to the README

zane 2022-01-03T09:59:27.011Z

Love it.

huygn 2022-01-03T10:19:43.011200Z

@gnhuy91 has joined the channel

2022-01-03T10:25:01.011400Z

@mmz has joined the channel

vinurs 2022-01-03T11:20:34.011600Z

@haiyuan.vinurs has joined the channel

borkdude 2022-01-03T12:02:34.012100Z

@zane Added a github workflow: https://github.com/babashka/obb/runs/4690744423?check_suite_focus=true

👍🏻 1
zane 2022-01-03T12:08:05.012400Z

Happy to just follow your lead on all the release engineering.

jeongsoolee09 2022-01-03T12:21:19.012700Z

@volcano0909 has joined the channel

zane 2022-01-03T12:50:12.013Z

Next highest priority is probably a better printer.

zane 2022-01-03T12:51:00.013300Z

$ obb -e '(range 10)'
I:null, start:0, end:10, step:1, $a:null, Ub:null, L:null, G:32375006, P:140800

borkdude 2022-01-03T12:54:26.014Z

@zane yes, the -e can just use prn

zane 2022-01-03T12:59:04.014900Z

prn will blow up on object specifiers, no?

borkdude 2022-01-03T12:59:32.015100Z

can make this conditional

👍🏻 1
zane 2022-01-03T13:03:55.015400Z

Yep. There are a few other small design decisions to make, e.g. whether we want to default to osascript’s “human readable” output for object specifiers and the like. From man osascript: > osascript normally prints its results in human-readable form: strings do not have quotes around them, characters are not escaped, braces for lists and records are omitted, etc. This is generally more useful, but can introduce ambiguities. For example, the lists ‘{“foo”, “bar”}’ and ‘{{“foo”, {“bar”}}}’ would both be displayed as ‘foo, bar’. To see the results in an unambiguous form that could be recompiled into the same value, use the s modifier.

borkdude 2022-01-03T13:07:51.015700Z

For nbb I've chosen to always use prn but we can fall back on console.log for object specifiers

borkdude 2022-01-03T13:08:06.015900Z

we could also default to no printing for normal scripts

👍🏻 1
borkdude 2022-01-03T13:08:19.016100Z

this is what nbb does

zane 2022-01-03T13:14:32.016500Z

Sounds like a plan.

borkdude 2022-01-03T12:54:38.014300Z

see how it's done with #nbb

borkdude 2022-01-03T12:54:55.014600Z

You can now install #obb with:

brew install babashka/brew/obb

🎉 2
tami5 2022-01-03T13:23:31.016800Z

@kkharji has joined the channel

rlhk 2022-01-03T13:41:49.017Z

@rlhk.open has joined the channel

rlhk 2022-01-03T13:44:10.017700Z

Great addition to then bb family. I guess https://github.com/Hammerspoon/hammerspoon could be replaced somehow?

zane 2022-01-03T14:08:39.017900Z

👍 2
borkdude 2022-01-03T14:10:08.018300Z

Nice for the examples dir maybe?

zane 2022-01-03T14:11:08.018500Z

Just added.

zane 2022-01-03T14:14:07.018900Z

obb -e '(-> (js/Application "Spotify") (.-currentTrack) (.name))'

zane 2022-01-03T14:14:10.019100Z

Lots of fun to be had.

borkdude 2022-01-03T14:14:22.019300Z

Aw yeah!

zane 2022-01-03T14:15:12.019700Z

obb ❤️ bitbar / xbar / swiftbar

zane 2022-01-03T14:15:30.020100Z

Put the result of any obb script in the menubar.

huygn 2022-01-03T14:16:02.020600Z

is there ways to explore these apps methods? 🤔

zane 2022-01-03T14:16:10.020800Z

Yes!

zane 2022-01-03T14:17:08.021Z

Open Script . File > Open Dictionary.

💯 1
zane 2022-01-03T14:17:29.021300Z

Be sure to change the language dropdown to “JavaScript”.

huygn 2022-01-03T14:17:35.021500Z

ah, cool!

borkdude 2022-01-03T14:18:38.021700Z

Ah, we need to add this trick to the README

👍🏻 1
borkdude 2022-01-03T14:18:54.021900Z

Maybe under FAQ

borkdude 2022-01-03T14:19:09.022100Z

or Tips and Tricks

borkdude 2022-01-03T14:21:54.022400Z

Is there a way to convert a spotify Track to a normal object?

borkdude 2022-01-03T14:22:02.022600Z

e.g to convert into a clojure map

zane 2022-01-03T14:24:34.022800Z

Trying to remember how to do that.

huygn 2022-01-03T14:31:13.023200Z

ObjC.unwrap(apps)? 🤔

huygn 2022-01-03T14:31:23.023400Z

saw it in the jxa doc

borkdude 2022-01-03T14:39:36.023600Z

anyway this works:

$ obb -e '(defn track->clj [track] {:artist (.artist track) :album (.album track) :name (.name track)}) (-> (js/Application "Spotify") (.-currentTrack) track->clj str)'
{:artist "The Gathering", :album "How to Measure a Planet? (Deluxe Edition)", :name "Travel"}

zane 2022-01-03T14:39:57.023800Z

@gnhuy91 I think that’s just for Objective-C objects.

huygn 2022-01-03T15:00:00.024500Z

(defn reminder->clj [reminder]
  {:name (.name reminder)
   :completed (.completed reminder)})

(-> (js/Application "Reminders")
    (.-defaultList)
    (.-reminders)
    (aget 0)
    (reminder->clj)
    (clj->js))
had fun with Reminders

👏🏻 1
borkdude 2022-01-03T15:02:34.024700Z

I guess since SCI supports macros, you could write a macro to do (->clj obj .name .completed) or so

huygn 2022-01-03T15:03:23.024900Z

yea that'd be less verbose

zane 2022-01-03T15:04:59.025200Z

Some returned objects will be records. For those there’s this: https://apps.apple.com/us/app/json-helper-for-applescript/id453114608

zane 2022-01-03T15:05:09.025500Z

Works on, e.g. http://Things.app tasks.

zane 2022-01-03T15:05:15.025700Z

That’s what I was trying to remember earlier.

zane 2022-01-03T15:05:44.025900Z

Location Helper is similarly helpful. https://apps.apple.com/us/app/location-helper/id488536386

borkdude 2022-01-03T15:16:13.026200Z

$ obb -e '(defmacro ->clj [obj & interops] (let [names (map #(clojure.string/replace (str %) #"[.-]" "") interops) ks (mapv keyword names) exprs (mapv #(list % obj) interops)] `(zipmap ~ks [~@exprs]))) 

(-> (js/Application "Spotify") (.-currentTrack) (->clj .artist .album .name) str)'
{:artist "The Gathering", :album "How to Measure a Planet? (Deluxe Edition)", :name "Travel"}

rwstauner 2022-01-03T14:30:16.023100Z

@clj149 has joined the channel

borkdude 2022-01-03T15:19:19.027200Z

Found a useful macro that will help with interop:

$ obb -e '
(defmacro ->clj [obj & interops]
  (let [names (map #(clojure.string/replace (str %) #"[.-]" "") interops)
        ks (mapv keyword names)
        exprs (mapv #(list % obj) interops)]
    `(zipmap ~ks [~@exprs]))) 

(-> (js/Application "Spotify") (.-currentTrack) (->clj .artist .album .name) str)'

{:artist "The Gathering", :album "How to Measure a Planet? (Deluxe Edition)", :name "Travel"}

💯 4
🚀 1
borkdude 2022-01-03T15:23:59.027700Z

Added to README: https://github.com/babashka/obb#macros

jesse 2022-01-03T15:24:09.028100Z

@jesse.claven has joined the channel

p4v4n 2022-01-03T15:24:37.028300Z

@p4v4n has joined the channel

2022-01-03T15:54:56.028700Z

@cldwalker has joined the channel

sgepigon 2022-01-03T16:01:45.028900Z

@sgepigon has joined the channel

chromalchemy 2022-01-03T16:35:38.029100Z

@chromalchemy has joined the channel

bmcgavin 2022-01-03T16:49:33.029300Z

@bmcgavin has joined the channel

pithyless 2022-01-03T18:02:48.029500Z

@pithyless has joined the channel

lread 2022-01-03T18:16:51.029800Z

@lee has joined the channel

zane 2022-01-03T22:16:01.031300Z

It would be nice to be able to extend IPrintWithWriter to support object specifiers, but I think the protocol retrieval logic will also crash on them.

borkdude 2022-01-03T22:28:46.031700Z

yeah, this is something that should be supported in SCI for other targets (nbb, babashka) as well.

borkdude 2022-01-03T22:29:48.032400Z

or do you mean, extending it in the precompiled obb? (yes, this is what you meant)

zane 2022-01-03T22:30:22.032700Z

Yes.

borkdude 2022-01-03T22:30:46.033300Z

what do you normally get with console.log on such a thing? also an error in JS?

zane 2022-01-03T22:32:08.034500Z

If an expression evaluates to one you get back something akin to JS code that will produce it:

>> Application("Safari")
=> Application("Safari")

zane 2022-01-03T22:32:31.034900Z

console.logging one will actually crash:

>> console.log(Application("Safari"))

!! Error: Error: Symbol.toPrimitive is not a valid class for application Safari

borkdude 2022-01-03T22:34:11.035900Z

so what is it actually doing when it prints that? not console.log I assume? is there a special method they call on the object specifier to get this string? I'll be afk now, back tomorrow 💤

zane 2022-01-03T22:34:19.036100Z

Yes.

zane 2022-01-03T22:34:33.036400Z

js/Automation.getDisplayString

borkdude 2022-01-03T22:35:20.036600Z

Ah I see:

$ time obb -e '(-> (js/Application "Google Chrome") (.-windows) (aget 0) (.-tabs) (aget 0) js/Automation.getDisplayString pr-str)'
"Application(\"Google Chrome\").(0).(0)"

👍 1
👍🏻 1
borkdude 2022-01-03T22:36:32.037600Z

and what happens if you extend the protocol to such a thing and then call this method on it?

zane 2022-01-03T22:36:52.038200Z

Right. I had thought to just

(extend-protocol IPrintWithWriter
  ...
  (-pr-writer [obj writer _]
    (if (object-specifier? obj)
      ...
      ...)))
but we don’t get to that -pr-writer implementation. It crashes before that.

zane 2022-01-03T22:37:17.038600Z

I’m trying to track down exactly what’s triggering the crash, but it’s hard. 😓

borkdude 2022-01-03T22:37:30.038800Z

what is on the first three dots?

zane 2022-01-03T22:37:55.039400Z

I’ve tried function, object, and default for the types.

borkdude 2022-01-03T22:38:05.039600Z

is there not a type like js/ObjectSpecifier that you can extend the protocol to?

zane 2022-01-03T22:38:21.039800Z

Sadly, no.

zane 2022-01-03T22:38:26.040200Z

>> typeof Application("Safari")
=> "function"

borkdude 2022-01-03T22:39:02.040700Z

we can also patch prn etc in the SCI context

zane 2022-01-03T22:39:48.041100Z

string-print, probably.

borkdude 2022-01-03T22:40:02.041400Z

probably. this stuff is in

borkdude 2022-01-03T22:40:23.041800Z

but I was thinking {:namespaces {'clojure.core {'prn ...}}}

borkdude 2022-01-03T22:40:40.042Z

in the SCI opts

borkdude 2022-01-03T22:40:54.042400Z

both are possible but the latter is less hacky.

borkdude 2022-01-03T22:42:22.042700Z

but if console.log also crashes the thing, I'm not sure if we should try to fix it

borkdude 2022-01-03T22:43:07.043300Z

don't improve on the JS behavior, just provide the same-but-CLJS behavior I'd say

borkdude 2022-01-03T22:43:37.043700Z

when printing the return value with -e it's a different story, but there we can just write our own thing

zane 2022-01-03T22:44:29.044100Z

Hmm. Fair!

borkdude 2022-01-03T22:45:08.044800Z

We could provide a safe-print function in obb.core though, something to think about.

zane 2022-01-03T22:45:13.045Z

Need to think about whether that’ll work if an OS is in a collection.

zane 2022-01-03T22:45:21.045300Z

Yeah, definitely.

borkdude 2022-01-03T22:45:23.045500Z

oh right