Not loving JXA

A few days ago, Brett Terpstra presented us TaskPaper users with a couple of Keyboard Maestro macros, one for natural language dates (e.g., “tomorrow” or “next Monday” in @due or @start tags) and one for incrementing or decrementing numerical values in tags like @priority(n).

As it happens, I don’t use TaskPaper in as formal a way as Brett does—experience shows that the more structure I put in my task management system, the less I use it—so I suspect I’ll never take advantage of Brett’s work. But tucked away in a footnote is a comment that rang true for me:

I’m still clumsy with JavaScript for Automation. As annoying as I’ve found AppleScript over the years, I’m just not loving JSA much more.

This is a perfect distillation of my experience with both AppleScript and JavaScript for Automation.1

The main problem with AppleScript is the tremendous variation in quality from one application’s dictionary to another’s. There are so many idiosyncrasies, it’s hard to remember which gimmicks apply to which app. JXA doesn’t—and can’t—solve that problem because it rests on the same Apple Events foundation as AppleScript. Worse, it adds a new problem: very little outsourced documentation.

By “outsourced documentation” I mean the vast collection of websites in which AppleScript programmers have written about the little tricks they’ve discovered to get their scripts to do what they want. For me, programming in AppleScript consists largely of working out in my head the overall structure of the script and Googling to find the right magical incantations for each individual part. Then revising the structure when I find that certain parts can’t be done the way I thought they could.

(There are, I’m sure, AppleScripters who don’t need to Google for syntax. I can’t imagine Doug Adams, for example, needing to search for help with the iTunes dictionary. But I’ve never scripted any single application long enough to master it, and even if I had, mastery of one app doesn’t necessarily translate to another.)

JXA doesn’t have that quarter-century of folk wisdom. So programming in JXA is just like programming in AppleScript, but with the extra step of translating someone’s AppleScript trick into JavaScript—a very different language.

When JXA was released, I really thought it would be superior to AppleScript. I imagined myself rewriting my old AppleScripts in this new, more normal language. But it hasn’t turned out that way. Like Brett, I am still clumsy with JXA and doubt I’ll ever get coordinated.

  1. And like Brett, I think JavaScript for Automation should be abbreviated JSA and usually write it that way. But Apple says it’s JXA (in documentation that still refers to macOS as OS X, but I’m not here to rant about how Apple’s enormous workforce can’t muster enough people to update the documentation for a line of products so small it could fit “on the table you’re sitting at”). 

Timers, reminders, alarms—oh, my!

I was shocked—shocked!—to see people disagree with my last post. I was even more shocked to learn about bizarre omission in the HomePod software. I decided to dig into the many ways you can set timed alerts on your Apple devices and how the alert systems vary from device to device. It is, you will not be surprised to learn, a mess.

Let’s start with the summary. In the table below, I’m comparing the features of the three alert types on iOS: Timers, Alarms, and Reminders. Included in the comparison is how certain features work (or don’t work) on the iPhone, iPad, Watch, Mac,1 and HomePod. Most of the entries for the HomePod are empty because I don’t have one to test, but I’ve included it because it was the device that got me started down this path. Also, there’s that software omission I want to talk about.

  Timer Alarm Reminder
Number 1 ∞︎ ∞︎
Name/Description No Yes Yes
Autodelete Yes No Yes
    iPhone Yes Yes Yes
    iPad No No Yes
    Watch Yes Yes Yes
    Mac No No Yes
    HomePod ? ? No
Time left
    iPhone Yes No No
    iPad Yes No No
    Watch Yes No No
    Mac No No No
    HomePod ? ? ?
Time of
    iPhone No Yes Yes
    iPad No Yes Yes
    Watch No Yes Yes
    Mac No No Yes
    HomePod ? ? ?

Many of the entries in this table have caveats, so let’s go through it.

The number of alerts that can be set was the starting point for the last post. People want multiple timers in their HomePods. That’s great, but Apple’s never had multiple timers in any iOS device, which is why I’ve always used reminders instead. “Reminders aren’t a substitute for timers!” I’ve been told by several people. I admire your steadfast adherence to your principles, but I need a solution, not a manifesto. (We’ll get to the deficiencies of using reminders as a substitute for timers later in the post.)

Since there’s only one timer, there’s no need for it to have a name or description. So when the timer on your phone/watch/table/speaker goes off, you might have to think a bit before you remember what it’s for. Alarms and reminders don’t have this problem.

I didn’t mention alarms in my last post, but Kirk McElhearn reminded2 me of them. If you’ve only used Clock app’s UI to set an alarm, you may think you have to use a specific time (like 8:55 PM) instead of a relative time (in 20 minutes). But Siri offers another way:

Hey Siri, set a casserole3 alarm for 20 minutes.

One problem with using alarms as your alert system is that they don’t delete themselves when you dismiss them; they just sit there, inactive, taking up space in your list of alarms until you undertake a second action to remove them from the list. Timers delete themselves upon dismissal, which is certainly more convenient. Reminders almost delete themselves—when you mark a reminder as complete, it gets hidden in the Completed list. I take this as close enough to deletion that I gave Reminders a Yes on the Autodelete line.

One of the biggest advantages to using reminders is that they’re shared via iCloud, which also syncs them to your Mac. This is very convenient if you use reminders during the workday and allow notifications from the Reminders app, which I do. Timers and alarms are not shared; the timer you set on your phone doesn’t appear in the Clock app on your iPad or on your watch. But the watch is special because of its intimate relationship with the phone. Your watch will alert you of a timer or alarm set on your phone, even though it doesn’t appear in the watch’s Timer or Alarms app. The Mac is ignorant of all timers and alarms.

Here’s where we get to the HomePod’s software omission. Even if you set up your HomePod to access your reminders—which, I admit, you may be reluctant to do in some households—the HomePod will not alert you when a reminder comes due. I was first informed of this stunning fact by Holger Eilhard, and it’s been confirmed by others. So I guess you can create a reminder through your HomePod but not be alerted by one. For whatever that’s worth. Because I don’t think it’s worth much, I decided to put a No in the Reminder column for sharing on the HomePod.

A feature many people find essential is getting the time remaining before an alert goes off. I would like to tell these people to chill out, take a Zen approach, that “a watched pot never boils,” but that would only anger folks who seem to be a little on edge already. My blithe assertion that timed reminders is the solution to the lack of multiple timers was based too much on my own use. In the 4+ years I’ve been using reminders for timed alerts, I have never wanted to know how much time was left, but I guess the rest of the world doesn’t slavishly model itself after me.

So if you need to know the time left on an alert, the timer is your only friend. Neither alarms or reminders will give you that. Alarms and timers will give you the time an alert will go off (like 8:55 PM), but you’ll have to do the subtraction yourself, which isn’t convenient.

By the way, although I put a Yes in the “Time of” section for the Watch, my watch has never actually been able to tell me the time a reminder is due when I ask it via Siri. It definitely understands me, and it acts like it’s going to retrieve that information, but it’s never finished the job. I can, of course, see the due time of a reminder using the watch’s Reminders app.

And there are also a couple of problems with asking Siri for the time of a reminder on the phone:

Siri reminder times

The obvious problem is that the time Siri says is wrong. And it’s been wrong every time I’ve tried this over the past two days.4 For this example, the reminder was set for 3:50 PM, but Siri told me a time six hours earlier. Now, I happen to live six hours away from UTC, so my first thought was that Siri was programmed (stupidly) to respond in universal time. But then I realized the six hour difference was in the wrong direction. 3:50 PM US/Central is 9:50 PM UTC, not 9:50 AM UTC. So Siri’s answer is so bad it isn’t even wrong in an understandable way.

The less obvious problem is Siri’s characterization of my casserole reminder as the “next reminder.” Inexplicably, she uses that phrase even if the reminder you ask about isn’t the next one. Sigh.

After going through this exercise, I will continue to use timed reminders because

I’ve said on Twitter that I think Apple intends timed reminders to be the substitute for multiple timers. I still think that, but I’m less certain now than I was a few days ago.

Update Feb 18, 2018 9:22 AM
There’s always more.

First, something I had scribbled in a note but forgot to put in the post: a timer may not sound an alert. If you like to fall asleep listening to music, you may have the Timer’s When Timer Ends setting assigned to Stop Playing.

Timer setting

If that’s the case, the next time you use Siri to set a timer, it won’t make a sound, which probably isn’t what you want.

Second, reader Thomas Shannon has emailed me that alarms go off only at minute markers. So if it’s 9:55:45 and you tell Siri to set an alarm for one minute, it will go off 15 seconds later. I was annoyed to hear this because I looked into this four years ago with regard to reminders and found that their alert times are not restricted to whole minutes. If you tell Siri at 9:55:45 to remind you of something in one minute, the alert goes off at 9:56:45.

I used to tell people the advantage of using Apple products was their consistency across devices and applications. I don’t do that anymore.

  1. You’re right, the Mac isn’t an iOS device, but it does work with Reminders, which can be very handy, so I’m including it. 

  2. Hah! I slay me. 

  3. I’m using casseroles in the examples because I’m a homespun Midwesterner (and not from Minnesota). 

  4. As I said above, I’ve never asked about the time of a reminder. Good thing, too. 

Friendly reminders

My vision of myself as a powerful thinkfluencer in the Apple world took a real beating this week. It seemed as if everyone who got a HomePod was complaining that it couldn’t set multiple timers. This is something I’ve written about a couple of times, going back four years. And I’ve explained the solution. Is this thing on?

Of course, four years ago, I wasn’t talking about the HomePod, I was talking about the iPhone, but the principle is the same. In iOS, the timer function is in the Clock app, and there’s only one. There’s no way to have two timers running simultaneously and no way to give your timer a name that lets you know what it’s for.

But you do have Reminders. They have names and can be set to alarm not only at an absolute time, but also at a relative time:

“Hey Siri, remind me to check the casserole in 20 minutes.”

Casserole reminder

This works on my iPhone, iPad, and Watch, and I assume—based on this article—that it would work on my HomePod if I had one. This is clearly Apple’s preferred solution to setting mulitple timers, each with a distinct name.

So I was frustrated to hear John Gruber and Paul Kafasis in the latest episode of The Talk Show complain about the multiple timer problem. They should both know how to use Reminders to solve this problem. So should Myke Hurley, who made the same complaint in the most recent Upgrade.

I understand where they’re coming from. If you’re an Amazon Echo user, you’re probably in the habit of saying something like

“Alexa, set a 20-minute timer for the casserole.”

Habits like that are hard to break, especially as you get older.1 But Apple users should be used to the idea that Apple has strong opinions about the right way to use its products and you’re usually better off not bucking the system.

You don’t like cluttering up your Reminders with hundreds of “check the casserole” and “check the tea” items? Even though you typically don’t see completed reminders? There is a solution.

In the past couple of days, the HomePod complaint industry has moved on from multiple timers to white rings. Cheaply made leather circles are already coming onto the market, but I’m going to suggest that high end furniture protection should come from lace doilies with tatting that complements the HomePod’s fabric pattern.

  1. Myke is 30 now, so his brain has lost much of its former plasticity. 

LaTeX contact info through Workflow

I’ve been writing more on my iPad recently; not just blog posts, but reports for work, too. Because I have a lot of helper scripts and macros built up over many years of working on a Mac, writing on the iPad is still slower. But I’m gradually building up a set of iOS tools and techniques to make the process go faster. Today’s post is about a Workflow I built yesterday with advice from iOS automation experts conveyed over Twitter.

For several years, I wrote reports for work using a Markdown→LaTeX→PDF workflow. For most of those years, it was rare for me to have to edit the LaTeX before turning it into a PDF. Recently, though, that rarity has disappeared, mainly because my reports have more tables and figures of varying size that need to be carefully positioned, something that can’t be done in Markdown. A few months ago I decided it would be more efficient to just write in LaTeX from the start. This wasn’t as big a change as you might think. I used to write in LaTeX directly, and the combination of TextExpander and a few old scripts I resurrected got me back up to speed relatively quickly—on the Mac, anyway.

On iOS, most of the TextExpander snippets I built for writing in LaTeX work fine, but the helper scripts, which tend to rely on AppleScript, don’t. One of the scripts I definitely wanted an iOS counterpart for was one that extracted the contact information from a client in a particular format. In my reports, the title page usually includes section for the name, company, and address of the client. This is added in the LaTeX source code by this:

\client{John Cheatham\\
Dewey, Cheatham \& Howe\\
1515 Loquitor Lane\\
Amicus OH 44100}

where \client is a LaTeX command I created long ago, and its argument needs the usual LaTeX double backslashes to designate line breaks. Also, ampersands, which are special characters in LaTeX, need to be escaped.

I thought I could whip something up in Workflow, but my limited understanding of Workflow isn’t conducive to whipping. When I first tried to put something together a couple of weeks ago, it looked to me as if I was going to have to painstakingly extract every piece of information from the selected contact, create variables to store them in, and then put those variables together into a new string of text. So I gave up.

Yesterday I decided to ask for help.

I would like to extract from a selected contact a standard name/address block as plain text:

Full Name
Street Address
City, ST Zip

I don’t think Contacts or Interact do this. Does anything?
  — Dr. Drang (@drdrang) Fri Feb 9 2018 9:37 PM

As you can see, I asked for something a bit simpler than what I really wanted, and I was kind of expecting suggestions for an app that would do the trick. But I soon got a response from Ari Weinstein with a Workflow solution:

Sample workflow from Ari

Since Ari is a co-developer of Workflow, I kind of figured he knew what he was talking about. But I didn’t, and it’s because I didn’t appreciate Workflow’s magic variables. I’ve always thought of Workflow as being almost like a functional language, where each action transforms the data passed to in and sends it along to the next action in turn. That, at least, is what I thought happened when the actions are connected by lines.

Which is why I didn’t understand Ari’s workflow at first. I figured that if it was extracting the Street Address in the second step, there’d be no way for it to get ahold of the Name and Company in the fourth step. What I didn’t appreciate was that there can be side effects the usual view of a workflow doesn’t show you. In this case, the Contact that’s selected in the first step is saved to a magic variable (called “Contact”) that remains available for use in later steps. So the third and fourth steps have access to all the Contact information even after the extraction of the Street Address in the second step.

Ari’s sample is a standard workflow that would have to be run from within Workflow itself or from a launcher app like Launch Center Pro. I was thinking about how to turn it into an Action Extension that could be called from within Contacts when I noticed I had a Twitter reply from Federico Viticci:

Sample workflow from Federico

His suggestion is set up as an Action Extension that accepts only Contacts and extracts the info from the Workflow Input magic variable. Just what I was going to do.

“My” final workflow, called LaTeX Address, combines what I learned from Ari and Federico and adds some search-and-replace stuff to handle the LaTeX-specific parts:

LaTeX address workflow

The first two steps create a text variable named Ret that consists of a single line break. We’ll see why I needed it in a bit.

Steps 3–5 are the Ari/Federico mashup. I couldn’t use Federico’s suggestion to just add Workflow input:Street Address to the end of the block because my contacts usually include the country, even though the country is almost always the US, and I didn’t want that at the end of the block. At some point, I’ll improve this by writing up a filter that deletes the country line only if it’s the US, but this will do until I get another job with a non-US client.

Step 6 escapes the ampersands, and Step 7 adds the double backslashes to the ends of each line. You need four backslashes to get two in the output because regexes need two to produce one. I thought I could use \n at the end of the replacement string to get a line break, but I couldn’t get that to work. Thus, the Ret variable defined at the beginning of the workflow.

Finally, Step 8 puts the text on the clipboard, ready for pasting into a LaTeX document.

My plan is to use this extension in Split View, with my text editor, currently Textastic, on one side and Contacts on the other. When I need to insert the client info, I find it in Contacts, tap Share Contact to bring up the Sharing Sheet, and select the Run Workflow action.

Textastic and Contacts

This brings up the list of Workflow Action Extensions that can accept Contacts. I choose LaTeX Address from the list, switch focus back to Textastic, and paste the text block where it belongs. Boom.

Pasting workflow result-

I’ll try to remember to look for magic variables the next time I make a workflow. There is a trick to making them visible. When you’re editing a workflow and can insert a variable (magic or otherwise), a button with a magic wand will appear in the special keyboard row.

Button to see magic variables

Tapping it will give you a new view of your workflow, with the magic variables appearing where the workflow creates them.

Seeing the magic variables

You don’t need to do this, as all of these variables should appear in the special keyboard row if you keep scrolling it to the right. But I find it easier to understand what they are and where they come from in this view.

Thanks to everyone who had suggestions for me, especially Ari and Federico.