Advertisement

Replicating QuickCursor using BBEdit and Keyboard Maestro

[Keyboard Maestro app icon]

QuickCursor was the first app I bought on the Mac App Store. It was a great utility which let you send text from any application to your favorite text editor, and then when you were done, it would send the text back from your favorite text editor to the original application. For example, if I was writing a lengthy response to a question on AskDifferent in my web browser but didn't want to lose my work if the browser crashed, I could use QuickCursor to write it in BBEdit instead. (If you're still not clear on the concept, watch the YouTube video for QuickCursor.)

Unfortunately sandboxing killed QuickCursor, meaning that it could no longer be sold through the Mac App Store. Jesse Grosjean, the developer, released the source code on GitHub because he was not planning to continue updating it. (Can't say that I blame him after making a great-but-niche-market app for the Mac App Store, only to have Apple change the rules and make it impossible to continue selling it in the Mac App Store.)

I am still hopeful that someone will revive QuickCursor as a non-MAS app, but until that happens, I needed a temporary solution.

BBEdit and Keyboard Maestro to the rescue, again.

My solution to this problem is called Edit Anywhere. It uses Keyboard Maestro and BBEdit to replicate most of the functionality from QuickCursor. (It would be possible to adapt this to other text editors as well. See the GitHub README for details.)

If you use those apps, all you have to do is download and import the Keyboard Maestro macro (note: make sure Keyboard Maestro is running before you try to import the .kmmacro file).

[BBEdit menu]

Also, you'll need to make sure that you have installed BBEdit's command-line tool. If you purchased BBEdit directly from Bare Bones, you can use the "Install Command Line Tools..." menu option as show in the image here. (If you aren't sure if they are already installed, go ahead and use the menu. It will tell you if they are installed and up-to-date.) If you purchased BBEdit from the Mac App Store, you will need to download and install the tools from BareBones.com.

How it works (Overview)

In Keyboard Maestro you will need to choose a keyboard shortcut to trigger 'Edit Anywhere.' I use Command+Option+Control+Shift+Q. (That might seems complicated, but I have remapped my Caps Lock key to equal Command+Option+Control+Shift, so all I have to press is Caps Lock + Q. See Brett Terpstra's "A Useful Caps Lock Key" for more information.) You can, of course, set the keyboard shortcut to be anything you want.

The macro tries to determine if you have selected text in the current application. If yes, it will only use that text. Otherwise, it will select all of the text from the current application. That text will be 'cut', saved to a temporary file in your Home directory, and then opened in BBEdit. When you finish editing the file, simply close it and you will be taken back to the app that you were using, and the text will be pasted back into place.

If, for some reason, the process does not complete successfully, you will still have the edited text on your pasteboard and you can manually paste it wherever you want. Also, after each temporary 'Edit Anywhere' file is used it is moved to your Trash, where it will remain until you empty it, in case you need to recover text from one of those files.

How it works (Nerdy Detail Level)

If you don't care how this works 'under the hood' feel free to skip this section. I provided it for people who might be curious how to make their own Keyboard Maestro macros.

If you download and import the macro into Keyboard Maestro, you should be able to follow along as I explain each step.

First the macro checks to see if there is a menu item named 'Cut' which is enabled. Most Mac apps have an "Edit" menu with Cut, Copy, Paste, and Select All as sub-menu items. This is a quick test to see if the user has selected text in the current application. It is not foolproof, but it will cover us for most of the cases, and when it fails, all it means is that we will send all of the text to BBEdit instead of just the selected text.

If the 'Cut' menu is not enabled, then we can assume that need to do 'Select All' in order to capture all of the text from the current application. We do this first by trying the menu item "Edit -> Select All" and if that does not work, we fall back on + A , the usual keyboard shortcut for 'Select All' in most apps.

(Again, this is not foolproof, but close enough for our purposes.)

Then I added a very short (0.2 seconds) pause to the Keyboard Maestro macro. When testing this macro, I found that some apps (notably Gmail compose 'windows' in web browsers) needed a little extra time to make sure that 'Select All' had selected all of the text. By trial and error I came up with 0.2 seconds which seemed reliable without adding too much of a delay.

Next we 'cut' the text using the menu "Edit -> Cut" if it exists or + X (the common keyboard shortcut for 'Cut' in most apps). Why 'Cut' instead of 'Copy'? Wouldn't 'Copy' be safer since it leaves the text in the original app? There are a few reasons:

  1. Sometimes you can 'copy' when you can't 'cut' or 'paste.' For example, you can select text on a web page, but you can't cut or paste back to it. Better to have the macro fail quickly than to offer to do something that won't work.

  2. If the selected text from the original application gets unselected for some reason (either because of some AJAX tomfoolery, or because the user pressed an arrow key or happened to click the mouse somewhere in the area), then when the replacement text comes back in, it might either a) intermix with the old text or b) be pasted in either before or after the old text.

  3. If the user happens to switch away from BBEdit while editing their text, and then went back to the source app and saw the original text, they might forget that it was opened in BBEdit and start making changes to the original text which is going to be overwritten when the revised text came back. It would be better for them to switch to the app and be surprised to see an empty window, which will hopefully remind them to check BBEdit.

  4. Although it might seem unsafe to 'cut' the text away, almost every single application will have an 'undo' option where they should be able to 'undo' the 'cut' and get their text back if something goes wrong with 'Edit Anywhere.'

Now, as soon as we have cut the text, we save it to the file ~/.edit_anywhere.txt using pbpaste which is Apple's command line tool showing the contents of the pasteboard. Normally that file should not exist (we'll see why in a moment), but what if it does? Should we just overwrite it with the new content? Absolutely not, that might be leftover text that the user had forgotten was there. Instead, if the file exists, we'll append the new text to the file and then open it. That might give the user a moment of confusion, but it's easy enough to remove the text they do not want, certainly much easier than trying to recover overwritten information!

Once the information is safely stored in the file, we will try to open it with /usr/local/bin/bbedit which is BBEdit's command line tool.

(N.B. if you wanted to use a different tool other than BBEdit, this is the line you would want to change to something else such as open -W -n -F *YourAppNameHere* "$FILE" but then you would need to add a way to switch back to the proper application after you finished editing, and you would have to quit YourAppNameHere instead of just closing the window, which is all BBEdit requires. BBEdit's command-line tool is also smart enough to activate the proper app after it is finished. You can see why I chose BBEdit, especially since it is already my preferred text editor.)

What do we do if bbedit fails, or doesn't exist? The macro checks the exit code of bbedit and if it is not 0 then it checks to make sure bbedit is where it is expected. If it isn't, we inform the user. If it is, we inform the user that although bbedit is in the right place, it did not work properly. We also send the error message to stdout using echo which Keyboard Maestro will show the user because the shell script action is set to "display results in a window."

Then we open the ~/.edit_anywhere.txt file in the default text editor, using open -W -t. (See man open for more details.)

Assuming that bbedit does exist successfully, the shell exits and Keyboard Maestro will read the contents of the file back to the clipboard (we could have done that in the shell using pbcopy < "$FILE"). Then the macro will paste using the Edit -> Paste menu item, if available, or ⌘ + V.

Finally we run another shell script. This one looks for the ~/.edit_anywhere.txt and moves it to the trash (~/.Trash/) but first it renames it using the current timestamp (YYYY-MM-DD–24h.MM.SS) and removes the leading '.' from the filename so it can be more easily seen if the user opens the Trash by clicking on the dock icon. This also prevents old versions from being overwritten in the Trash, in case the user needs to retrieve one for some reason.

It's a start

'Edit Anywhere' isn't a perfect replacement for QuickCursor and, quite frankly, I'm still irritated that Apple failed to work harder to find ways to help developers make the transition into sandboxing. Too many good and useful apps have been either abandoned or forced out of the Mac App Store because of Apple's sandboxing implementation.

That said, 'Edit Anywhere' gives me most of what I needed as an alternative. I've only been using it for a short while, so there may be some weird bugs and edge cases out there, but I've tried to make it so that the worst thing that would happen is that you have to open your Trash and grab a text file. That said, I can't guarantee that you won't run into problems, so use as your own risk.