What’s next?

Last week, Guilherme Rambo was the the unofficial guest on every Apple-centric podcast. His inside information on what’s coming in macOS 10.15 and iOS 13 gave everyone something to anticipate, dread, or argue about. I want to talk about his last revelation of the week, that Shortcuts is coming to the Mac and what I hope that means.

Let’s start by noting, as Jason Snell did, that Rambo doesn’t use the most definitive language on this topic. First, he says

According to people familiar with the development of macOS 10.15 – which has been in the works for at least two years – the new version will include support for Siri Shortcuts…

OK, “support for Siri Shortcuts” may simply mean that apps will be able to suggest voice activation of certain actions. To me, this is the least interesting part of Shortcuts, because it’s basically limited to the automation of single steps. To be sure, these single steps sometimes take several taps or swipes to get at, so their activation with one “Hey Siri” is a real benefit, but they’re nowhere near as useful as the more complex combinations you can achieve through the Shortcuts app.

But then there’s this:

It’s also likely that the Shortcuts app – a result from the acquisition of Workflow – will be available on macOS, the inclusion of system-wide support for Siri Shortcuts on macOS 10.15 strongly suggests it.

Here, the prediction is for the Shortcuts app itself, which would be much more useful, but it’s weakened by “likely” and “strongly suggests.” Rambo seems to be drawing an inference about the introduction of a Mac Shortcuts app rather than having a source saying it’s coming.

And then there’s this:

According to sources, only Marzipan apps will be able to take advantage of the Shortcuts support on macOS.

Here we have actual sources, but it’s not clear what aspect of Shortcuts is being discussed here. My guess is that it’s just Siri Shortcuts, not a Shortcuts app. And of course, there’s the disappointing—but not surprising—limitation to Marzipan apps only.

Regardless of what comes to the Mac in 10.15, it seems inevitable that Marzipanification will eventually lead to a Mac Shortcuts app. Which raises the question of how Shortcuts will fit within the Mac automation environment. I want to expand on what Jason said in his last paragraph:

In the long run, Shortcuts for macOS needs to be able to access all sorts of low-level Mac features that its iOS counterpart can’t do, via support for shell scripts and AppleScripts. (The ability to run scripts is really Automator’s killer feature.)

Here’s the current state of scripting on the Mac:

Current Mac automation

At the base of macOS is Darwin, a BSD-style Unix. This can be scripted by all the usual Unix tools: Bash, Zsh, Perl, Python, Ruby, and so on. Sitting on top of that is all the Mac-like stuff, which gets scripted by AppleScript (ported over from the classic Mac OS) and Automator.1 The ability to script at both levels is very nice, but what makes this system so flexible as an automation environment are the connections between the two environments.

AppleScript can pull up Darwin-level information by running shell scripts through the “do shell script” construct, and Automator can do the same through the Run Shell Script action (Jason’s killer feature.). Just as important, though, is the ability for scripts at the Darwin level to access Mac-level information by running AppleScripts via the osascript command and Automator workflows via the automator command.2 Users can create their automations at the level that seems the most appropriate, confident that they can reach up or down to get whatever they need.

When Marzipan gets layered on top of the Mac and Shortcuts comes along to automate it, we’ll have this situation.

Future Mac automation

The big question is how will Shortcuts connect to the layers underneath it. Jason’s concern about the upward-pointing arrows along the left side of the diagram—will Shortcuts be able to run scripts and access the resulting information from the Macintosh and Darwin levels?—worries me, too, but I’m just as concerned about the downward pointing arrows along the right side of the diagram. Will AppleScript and shell scripts be able to run Shortcuts and access information from Marzipan apps?

My concern stems partly from my overall belief that an automation environment that shares in both directions is the most flexible. More specifically and selfishly, though, I have current automations that run in both directions, and I’m worried that those will be killed off if the main Mac productivity apps go Marzipan. For example, my system for sending and following up on invoices at work, which I discussed in this post and this episode of the Automators podcast, uses Keyboard Maestro to call a Python script that runs a couple of AppleScripts—it runs up and down both sides of the current diagram. If the Contacts and Reminders apps on the Mac become Marzipan-only and don’t give me connections between the upper and lower layers on both sides of the diagram, that system will stop working, and I will be very angry.

The people who built Unix understood the value of passing information back and forth between processes, and they gave that ability not just to C programmers but also to regular users through pipes, redirection, and shell scripting. The NeXT developers who built the Mac’s current OS maintained that tradition and extended it from the command line to GUI apps by hooking into AppleScript and Apple Events with osascript and do shell script.

We all know, though, that latter-day Apple has blown hot and cold on user automation and on opening up interprocess communication to the rest of us. The introduction of Shortcuts at last year’s WWDC suggests we’re currently in a hot phase, and I hope the connections necessary to make Shortcuts on the Mac a truly valuable tool get made before interest cools again.


  1. To this level, you could also add Keyboard Maestro, Hazel, and other third-party apps, but I’m listing only Apple-supplied features. 

  2. You can also run AppleScripts in Automator via the Run AppleScript action, but because that’s working at essentially the same level, I’m not going to talk about it here. It would be like discussing Perl’s backticks or Python’s subprocess module. 


Some PCalc stuff

My PCalc setup tends to stay the same for long stretches of time—it’s a stable app, and I’ve settled into a comfortable way of using it. But I did make some small adjustments a couple of months ago and thought you might be interested.

First, I moved some of the function buttons in my customized “Drang” layout. It now looks like this with the standard and 2nd functions:

My PCalc vertical layout

Apart from a little rearranging of the gray buttons, the main change is removing the gamma function (which I never use and had in there only because it fit as companion to the factorial) and replacing it with a combination function, yCx. It’s in the second row, third button from the left.

I say “a combination function” instead of “the combination function” because the built-in combination function, which is in the Special functions group, organizes its input and output in ways I don’t like.

Let’s say we wanted to find the number of combinations of 10 items taken 5 at a time. The input and output using the built-in combinations function look like this:

Built-in combinations function

There are two things I don’t like about this:

  1. The inputs are in reverse order, at least according to the way I think. When I think of combinations, I always think of the total number of items first and the number chosen second. In my head are the phrases “10 items taken 5 at a time” or “10 choose 5.” So my history with the built-in combinations function has been to enter the arguments that way, get an error message, then swap the inputs and redo. I finally got fed up with this and decided that PCalc should bend to my will rather than the other way around.
  2. The output is just one number, but PCalc gives me two. I can understand why James Thomson, PCalc’s developer, did it this way, because built-in functions should accommodate both Algebraic and RPN modes and there’s a symmetry to having both the input and output with numbers in the x and y registers. But I don’t use Algebraic mode, and the extraneous zero in the y register gets in the way of other items I may have further up the stack. Again, PCalc isn’t the boss of me.

So I rewrote the combinations function to fit the way I think and work. Now if I want to get the number of combinations of 10 items taken 5 at a time, I enter the 10 and 5 in that order and tap the yCx button. The input and output look like this:

My combinations function

Here’s James’s code for the built-in combinations function on the left and my code on the right:

Comparison of combinations functions

As you can see, I just stole James’s code and changed the beginning and ending bits to match my preferences.

(As a side note, you can also see that PicSew, which I used to make the extended screenshot on the right, uses a slightly darker iPhone frame image than Federico Viticci’s framing shortcut, which I used for the standard screenshot on the left.)

On my iPads, PCalc is usually my Slide Over app, ready to be pulled out from the right side of the screen whenever I need to do a quick calculation.

PCalc as Slide Over app

The layout is stretched vertically a bit more than I’d like—especially on the 12.9″ iPad, as shown above—but I haven’t felt the need to customize it for this use.

I may be unusual among PCalc users in that I use it as a calculator instead of an AR gaming platform. Despite the many other options I have for crunching numbers on iOS, it’s the app I turn to most often.


Back to LaunchBar

Back in October, after over ten years of using LaunchBar, I decided to give Alfred a try. Five months is, I would say, a fair trial, and while there were a few things about Alfred I preferred, last week I returned to LaunchBar and am happy to be back.

The obvious question is why did I switch in the first place? After getting a new iMac in late 2017, I noticed that LaunchBar wasn’t as smart on that machine as it was on my 2012 iMac (which I had moved from my office to home and am still using). I assumed this was because LaunchBar needed some time on the new computer to learn my habits, but even after the better part of a year, it still seemed to be making mistakes, especially when predicting which folder I wanted to open. I was pretty sure the indexing rules on the new iMac were the same as on the old one, so the difference in behavior didn’t make sense to me. Some corruption in whatever internal database LaunchBar uses to make and update its predictions?

Since I was considering wiping LaunchBar from the 2017 iMac and starting over from scratch, I thought it might be a good time to give Alfred a try. It and LaunchBar do roughly the same thing and seem to be equally well thought of among Mac power users. So I installed it and the Powerpack on both computers, training it in my habits and myself in its habits.

LaunchBar and Alfred are both launchers, apps that I always consider to be successors to the legendary Quicksilver1 but which most people probably think of as similar to Spotlight. Like Spotlight, they use a keyboard shortcut to bring up a floating text entry field. Depending on what you type into that field, the launcher may

Launchers, especially their ability to dig though a folder hierarchy in one step, are one of the main reasons I find certain types of work much easier on a Mac than on an iPad. Once you get acclimated to using one, you find working on a device that doesn’t have one like working with mittens on.2

Given the overlap in features, my ultimate preference for LaunchBar over Alfred comes down to just a few differences:

Update Apr 14, 2019 2:09 PM
A tweet from Tom Grimwood-Taylor alerted me to a way to get Alfred to (probably) activate with the last action ready to go. Turn on the “Show latest query if within 5 minutes” option in Alfred’s advanced preferences.

Alfred advanced preferences

I had the “Store typed query” option set. Don’t know why I didn’t set its neighbor. Thanks, Tom!

The biggest advantage Alfred has is patience. LaunchBar requires you to enter your search term within a certain amount of time (which can be adjusted in its Preferences); Alfred gives you as much time as you need to think about what you’re looking for and see how the search results change as you type more. While this isn’t enough to make me stay with Alfred, it does comes in handy sometimes. When I returned to LaunchBar this week, I increased its Retype Delay setting from 0.75 seconds to 1 second.

LaunchBar general preferences

After returning to LaunchBar, I did some tweaking to its Indexing settings, and it seems to be doing a better job of predicting my searches.

Despite my return to LaunchBar, I don’t regret my five-month detour into Alfred. It’s good to go off every once in a while and see how other people get their work done. My time with Alfred has me considering different ways of using LaunchBar.

One thing (not inspired by Alfred) that I’m considering is getting into HoudahSpot for more refined search filtering. John Voorhees’s article in MacStories did a good job of showing what the new HoudahSpot 5 can do, but I was still reluctant to add yet another app to my toolbox.3 It was when I saw Jason Snell’s note that I got more interested, as being able to run HoudahSpot’s filtered searches within LaunchBar would be a good fit for how I work.


  1. That I consider LaunchBar to be a Quicksilver successor doesn’t mean it is, it just means that I came to it after Quicksilver. As I was informed by Roben Kleene, LaunchBar goes back to the NeXTSTEP/OPENSTEP days. Which, frankly, I should have guessed from the name of the developer, Objective Development. 

  2. Apps like Shortcuts and Launch Center Pro are great, but iOS simply doesn’t allow them to have the power and range of apps like LaunchBar and Alfred. 

  3. David Sparks and Brett Terpstra have written about HoudahSpot in the past, and I’ve had the same yeah, but… reaction. 


Turning the tables

The current episode of Rosemary and David’s Automators podcast has me as a guest. You should go listen, especially if you want to hear me bitch about Shortcuts as a programming environment.1

One topic that came up briefly was Airtable, the cloud-hosted database with an exceptionally well-documented API. As I wrote about back in the fall, I’ve been using Airtable as, among other things, a handy means of having basic information on all of my work projects available to me on all of my computing devices. The Airtable database was converted from an SQLite table that I’d been using. As I said in the post, I was looking for something a little friendlier than SQLite:

As I found myself wanting to search the database on my phone and iPad, I moved the [SQLite] database file to iCloud Drive and wrote some scripts in Pythonista to do the searching. This worked, but it was a little clumsy and the results, while correct, were ugly. I didn’t really want to put in the effort to make the output prettier, but I was resigning myself to get down to it when Airtable appeared in my Twitter feed.

Aesthetics aside, Airtable allowed easier ad hoc searching than SQLite, mainly because SQLite is typically accessed either programmatically or though SQL queries, neither of which are easy to construct on the fly.

But after a few months of using Airtable, I came to realize that the great majority of my searches could be handled in one of two ways:

  1. Show me the ten most recent projects. It’s when I first start working on a new project that I tend to forget the project’s name and number and need to consult the database. A short list of the most recent projects—not even a real search—is the quickest way to get the info I need.
  2. Find the projects with a particular search term used in the project name, project number, client name, or client company. Usually I can remember at least one of these things but have forgotten one of the others. An SQL query of one particular pattern,

    select name, number, client, email from projects where
    client like <term> or name like <term> or email like <term>
    or number like <term>
    

    will do the trick.

In other words, most of time Airtable’s flexibility is of no use to me. And I was finding that the time it took to launch Airtable, select the projects database, and (sometimes) re-sort the fields was not a fair price to pay for flexibility I seldom used.

Fortunately, I had never given up the SQLite database. All of the new projects opened since I started using Airtable had been entered in both Airtable and SQLite.2 So all I had to do was pull out an old Python script for querying the SQLite database and tweak it to handle the two common situations.

As important as the scripting, though, was how to run the scripts on iOS. My first thought was to do it through Shortcuts, because that’s become the hot new thing, but David Barnard’s appearance on Automators reminded me of how fast Launch Center Pro is at running Pythonista scripts, especially since I could access them directly from the home screen by enabling QuickActions.3

LCP Quick Actions

The Pythonista script that returns the ten most recently added projects is this:

python:
 1:  import sqlite3
 2:  import console
 3:  
 4:  # Initialize projects database
 5:  pl = 'projects.db'
 6:  db = sqlite3.connect(pl)
 7:  query = 'select name, number, client, email from projects'
 8:  
 9:  # How many recent projects to return
10:  count = 10
11:  
12:  # Perform the query and print the results
13:  results = db.execute(query).fetchall()
14:  if len(results) == 0:
15:    answer = "Not found"
16:  else:
17:    lines = []
18:    for r in reversed(results[-count:]):
19:      # Older entries have empty client and/or email fields.
20:      if r[3]:
21:        lines.append('{}  ({})\n{}\n{}'.format(*r))
22:      elif r[2]:
23:        lines.append('{}  ({})\n{}'.format(*r[:3]))
24:      else:
25:        lines.append('{}  ({})'.format(*r[:2]))
26:    answer = '\n\n'.join(lines)
27:  
28:  console.clear()
29:  console.set_font('Helvetica', 20)
30:  print(answer)
31:  console.set_font()

The projects.db SQLite file is saved in the same directory as the script, so the connection to the database in Line 6 is simple. So is the query in Line 7, as it is not doing any actual searching, it’s just returning certain fields from all the records in the database.

Line 13 executes the query, and if nothing went wrong, Lines 18–26 assemble the answer in a reasonably readable format. The key is Line 18, which reverses the results list (putting the most recently added projects at the top) and truncates it to ten items. Lines 19-25 adjust the output according to the information available. If all four fields—project name, project number, client name, and client email—are available, each item will be arranged like this in Pythonista’s console,

Kernighan Project (9999)
Dennis Ritchie
dmr@unix.org

and there will be blank lines between projects.

Lines 28–31 handle the formatting of the console and the printing. I set the font to 20-point Helvetica in Line 29 to make the output a bit easier to read. Sending an empty argument to the set_font function resets the console to the default font in Line 31.

The name of the script is recentProjects.py and it’s saved in iCloud Drive. In Launch Center Pro, the Recent action runs this script:

Recent action in LCP

The URL is

pythonista3://recentProjects.py?root=icloud&action=run

The script that does actual searching of the database is called searchProjects.py and looks like this:

python:
 1:  import sqlite3
 2:  import console
 3:  
 4:  # Initialize projects database
 5:  pl = 'projects.db'
 6:  db = sqlite3.connect(pl)
 7:  query = 'select name, number, client, email from projects where client like ? or name like ? or email like ? or number like ?'
 8:  
 9:  # Get the search term
10:  input = console.input_alert('Project Search Term').strip()
11:  arg = '%' + input + '%'
12:  
13:  # Perform the query and print the results
14:  results = db.execute(query, (arg, arg, arg, arg)).fetchall()
15:  if len(results) == 0:
16:    answer = "Not found"
17:  else:
18:    lines = []
19:    for r in reversed(results):
20:      # Older entries have empty client and/or email fields.
21:      if r[3]:
22:        lines.append('{}  ({})\n{}\n{}'.format(*r))
23:      elif r[2]:
24:        lines.append('{}  ({})\n{}'.format(*r[:3]))
25:      else:
26:        lines.append('{}  ({})'.format(*r[:2]))
27:    answer = '\n\n'.join(lines)
28:  
29:  console.clear()
30:  console.set_font('Helvetica', 20)
31:  print(answer)
32:  console.set_font()

The difference between it and recentProjects.py is the query in Line 7 and that it gets the search term from the user via Lines 10. The dialog box that pops up to collect the search term is this:

Search term dialog

Line 11 takes the search term and surrounds it with percentage signs. This, along with the question marks in Line 7, is the query syntax required by the sqlite3 module.

The rest of the script is the same as before, and the LCP Search action looks just like the Recent action except the URL is changed to

pythonista3://searchProjects.py?root=icloud&action=run

So now I have the best of both worlds: a very fast system via SQLite, Pythonista, and Launch Center Pro for doing what I do most often; and a more user-friendly system via Airtable for doing more unusual searches.


  1. Although we had talked about HyperCard earlier in the program, I didn’t think to mention how much better programming in HyperCard was in the late 80s than programming in Shortcuts is in the late teens. A missed opportunity for a stereotypical cranky old man rant. 

  2. I didn’t want my database lost if Airtable was bought out and “sunsetted.” 

  3. The Scanner Pro quick action is what I use to grab expense receipts when I’m traveling.