Chetan Kunte recently sent me a TextExpander experiment he was working on, and I thought I’d post it and my explorations of it. It’s designed to add auto-pairing for bracket and quote characters to MarsEdit, and it’s based on a bit of information that I hadn’t been aware of before.
The basis for the script is the fact that–little to my knowledge–TextExpander traps a delimiter sequence and leaves the selection in place while it expands it. This means that if your shell/AppleScript snippet wants to access the selected text after a single-character trigger, it can. It doesn’t store this information within TextExpander, so it takes some AppleScript shenanigans to get the selection from any given program. This is hugely frustrating because “selected text” is handled differently in almost every app, leading to a thousand permutations if you want a universally-capable snippet. However, it works, and the solution that Chetan came up with is a great start on this.
The experiment also makes use of a trick I learned from Joe Workman which allows you to call a “library” shell snippet within other snippets to create a “require” statement and reuse code within other snippets. In this case, it’s calling an AppleScript to get the selection from MarsEdit and insert it between characters. If there’s no selection, you get paired characters.
|Chetan’s first version is available on github. My first addition to this script was to add a “%||” cursor placement so that your cursor was between the paired characters after expansion. I also added a block to check the frontmost app and allow the script to be expanded to any AppleScript-able application. TextEdit is the only additional app I’ve worked out so far. My version is available as a fork of Chetan’s on github. You can download or subscribe to it using the raw version of the TextExpander group. Set up the group so that it only expands in the applications you have scripted for; by default this is just MarsEdit and TextEdit. The application-specific settings are available when you select the group’s folder icon after installing it in TextExpander.|
As you can see in the screenshot to the right, the group consists of one AppleScript for gathering the selection (load the TextExpander group to see the actual script), and a series of plain text snippets that call the AppleScript snippet using the
%snippet:triggername% syntax. In mine (shown), the
%| places the cursor before the right character of the pair after expansion. Each snippet is triggered with the left character; in the case of square brackets, you would select text and type
[. If no text is selected, you’ll just get “”, otherwise your selection will be wrapped in square brackets.
Then I went down a rabbit hole… I really wanted more intelligent pairing so that it wouldn’t pair if there was a character to the right, and would skip a character right if the adjacent character was already a quote. TextMate style. This proved to be nearly impossible, but you can find my experiments in this area in a branch off my main repo. The biggest issue is that I can’t control cursor placement from an AppleScript snippet. I could probably rewrite the whole thing to include a repeat AppleScript for each set of pairing characters, then call them from another set of plain text snippets, but I pulled myself out of the hole before I got too invested in it. If anyone finds a solution before I dive back in, I’d love to see it!