I am pretty excited at the release of the new Coda plug-in SDK and I have been investigating it in preparation for building a Coda integration plugin for MenuMachine 3. As an exercise, I decided to try building a small, useful plug-in. I noticed that several people on the coda-users mailing list were bemoaning the fact that there was no “smart symbol wrapping” functionality in Coda, such as exists in TextMate.
Smart symbol wrapping is a neat feature for coders. The way it works is that you select some text in the editor and then press a particular symbol key, such as a square bracket. This key press is intercepted and the selected text is automatically wrapped in a pair of square brackets. Smart symbol wrapping handles all the various types of paired symbols, such as braces, parentheses and several other types of symbols such as quote marks.
I decided to write a Coda plug-in using the Cocoa API to implement this feature, which turned out to be reasonably straightforward. The resulting plugin, Wrapster, can be downloaded here.
Please note that you must be running Mac OS 10.5 (Leopard) in order to use this plugin.
The plug-in is open source and released under the MIT License. You can find the source in the plug-in’s bundle wrapper by selecting the plug-in in the Finder and choosing “Open Package Contents” from the Finder’s contextual menu.
The plugin uses a simple property list file (WrapOptions.plist, again in the wrapper) to configure the replacement characters so you can add to or modify the replacements that ship with it, which are:
{ } [ ] ( ) < > " ' “ ” ‘ ’ `
The WrapOptions.plist file contains a comment with instructions for how to edit the file.
You can enable and disable Wrapster in the Plug-Ins menu in Coda.
In terms of implementation, the only slightly tricky thing was finding a way to detect key events before Coda gets hold of them. It turns out that the only way to do this without having access to the internals of Coda is to use an Event Tap, which allows the plugin to capture the raw events posted from the keyboard before Coda’s NSApplication instance gets a chance to process those events. This does mean that in order to use the plug-in, you need to enable “Access for assistive devices” in the Universal Access System Preferences pane, as shown below. If you don’t do this, Wrapster cannot get access to any key events.
I hope you find this plug-in useful. It certainly has served its purpose for me, I’m pretty familiar now with the Coda SDK and what can be done with it. The guys at Panic have done a great job with the API which is simple and well thought out.
I’d love to hear your feedback about the plug-in (good and bad!).
Update: It seems that Wrapster was preventing Command-] and Command-[ from working. I’ve updated it to version 1.1 and it will now not replace the text if either the Control or Command keys are down, it will just pass the key press through to Coda.
Update 2: Justin on the coda-users mailing list pointed out that Wrapster would activate if text was selected in the page and you entered one of the special characters in the search field. I’ve fixed this now with version 1.2, Wrapster will now only activate when you are actually editing text. Get the update here.
Update 3: Thanks to Rainer Brockerhoff who alerted me in the comments to a more efficient way of handling the Quartz Event Tap that Wrapster uses to capture key events. I’ve updated Wrapster to 1.2.1 and incorporated his suggestions. There is no real need to update to this latest version unless you just absolutely must have shiny new stuff
.
Update 4:Thanks to Will Cosgrove from Panic who pointed out that one of the Apple methods I was using to intercept key press events is buggy and can cause a hang in the window server (this means a total UI lockup, very bad!). I have modified the code to make things safer. All users should update to the new version 1.3.

November 14th, 2008 at 6:34 am
Bravo, I’ve never seen this sort of functionality before and I’m already getting attached to it… I’ll definitely be using this alot I think.
November 14th, 2008 at 7:33 am
Awesome, thanks for this. Will use.
November 14th, 2008 at 7:34 am
Very exciting! Nice job! You’ll have to forgive my ignorance, but the fact that you’ve written something like this makes it seem as though tab-stop snippets (a la TextMate) may be a possibility after all. Based on your experience with the API so far, do you have any thoughts on that?
November 14th, 2008 at 7:36 am
simple and extremely useful, sweet.
November 14th, 2008 at 8:44 am
I ran into an issue where i hit decrease/increase tabbing on a selection (cmd-[ etc.), which triggers Wrapster. Obviously I can disable Wrapster in the menu, but that can get old.
What if Wrapster could ignore any key combo containing the cmd key?
November 14th, 2008 at 9:38 am
@BILLYD thanks for the heads up, I’ve fixed this so you can go ahead and download the new version.
November 14th, 2008 at 9:46 am
@Jonathan Christopher: Yes, you could use exactly the same method to do tab-completion of snippets a la TextMate. Not a bad idea…
November 14th, 2008 at 11:21 am
Awesome awesome! I am getting very close to switching over to Coda for my development!
I’m not sure this is possible or not, but is there a way to have Wrapster know to delete the second character if I delete the first?
What I mean is:
Open a new document….type ” (which results in “”) then hit backspace. The 2nd ” still remains.
Thank you very much for this plugin.
November 15th, 2008 at 4:02 am
@Rob Keniger: You don’t know how happy that makes me to hear. I brutal honesty, if the snippets functionality in TextMate is replicated in a Coda plugin, I can’t fathom how many more users Coda will gain. I’ll anxiously be waiting for that plugin to be released (by someone, sometime).
November 16th, 2008 at 3:26 am
Wow. Coda more powerfuller.
November 16th, 2008 at 9:46 am
Thank you! This is something I have been missing in about any code editor out there.
There’s only one thing that stops this from being perfect;
I would like to be able to select a block of text and then press “tab” to add an extra tab in front of every line.
Add this and I will create a religion in your name.
November 29th, 2008 at 10:42 am
Great plugin, immediately when I saw Coda was introducing plugin capability this is what I dreamed of. I have no complaints, only a question. In future editions will it be possible to have an entire string act as the key trigger? Such as if I want to wrap a stylesheet file name around its tag and trigger this by highlighting the filename and typing ‘css’ or such. There are only so many keys on the keyboard and I’ve filled most of them up with nice wrappers! Thanks a bunch
December 5th, 2008 at 9:23 pm
I just my hands on Coda (I must be one of the last) this little plug-in is awesome. Thanks.
December 6th, 2008 at 11:09 pm
Hi Rob. Was looking at your code. May I suggest that you do a per-process tap instead of a global tap? Call CGEventTapCreateForPSN() and pass kCurrentProcess as the PSN.
This will be more efficient and you don’t have to test if Coda is active, either.
December 7th, 2008 at 12:00 pm
@Rainer:
An excellent suggestion, thank you. I must admit I simply missed that function when I looked through the docs, this is the first time I’ve had to delve into Quartz event taps.
I’ve updated the code. I had to use GetCurrentProcess() to create the psn as for some reason constructing it using ProcessSerialNumber psn = { kNoProcess, kCurrentProcess } didn’t seem to work.
I’ve also incorporated the improved Accessibility checking as outlined on your blog. Many thanks.
December 21st, 2008 at 5:21 am
Simply amazing!
Great work! Thank you very much!!!
I can definitely see a light at the end of the tunnel, in regards to emulating more of TextMate’s functionality in Coda. I still have to do hardcore text editing in TM, but hopefully with stuff like this I’ll need to turn to it less often.
December 31st, 2008 at 11:13 pm
I posted in the Coda-Users GoogleGroup — about a problem I was having where Coda would effectively lock up (or become really, really slow) while Wrapster is enabled.
You had asked me to post my config file (.plist) and some other related info.
I basically added this (you can see the actual options in my plist further down):
Wrapper for triggered by “1″
Wrapper for triggered by “2″
Wrapper for triggered by “3″
I didn’t *like* the idea of using such common/popular keys (especially keys that I’m CONSTANTLY using in Coda (with Command) to switch modes).
FWIW, the wrapping WORKS. I can select anything and press “1″ and it wraps it in an H1. I just get an occasional major slow down or lockup — where Coda’s CPU utilization sits at around 7 or 8 percent — but it wholly unusable during this time. As long as I keep Wrapster out of my plugins folder, the Coda lockups/slowdowns don’t happen. When it does happen, I basically have to ForceQuit, but I get NO ERROR REPORT, and NO Crash Reporter Logs or anyting like that. Nothing in Console (All Message, Console Messages, etc…)
I didn’t know where else to look for logs, etc.
Please let me know if there’s anything else I can provide. Hopefully I’m not sending you on a wild goose chase.
My .plist file: http://drop.io/wrapster_stuff
*** Just click on the “download link” — and ignore the fact that it says “0K” — when it downloads, the file is in-tact.
Also, here’s a copy/paste of it, in case you don’t want to bother with drop.io
[
[%@]
]
[%@]
{
{%@}
}
{%@}
(
(%@)
)
(%@)
"
"%@"
'
'%@'
`
`%@`
>
<%@>
<
<%@>
“
“%@”
”
“%@”
‘
‘%@’
’
‘%@’
1
<h1>%@</h1>
2
<h2>%@</h2>
3
<h3>%@</h3>
January 7th, 2009 at 3:09 am
This is the best plugin yet. One thing I’m trying to do is us the “a” key to quickly create a link, it seems that using the selected text for the href and the text doesn’t work. It results in (null) for the text.
a
<a href=”http://%@” >%@</a>
January 7th, 2009 at 10:13 am
At present it will only do one substitution, I could certainly change this though.
January 8th, 2009 at 5:07 am
Thanks Rob, for this instance, after thinking about it, it might be better just to have one substitution. But, some might want that.
Another question, would there be a way to select where the cursor ends up?
Great plugin, thanks again!
January 25th, 2009 at 11:13 am
Awesome! Thank you so much for this plugin. Keep up the with the great ideas.
April 8th, 2009 at 11:17 am
Somebody has to make a version of this plugin for 10.4.11 Tiger, it’s just not fair that Leopard gets to have all the cool stuff lol
April 24th, 2009 at 2:09 am
I modified Wrapster to allow me to drop in certain HTML tags around selections, like p for paragraph, d for div, 1 for H1, etc… but I’m finding that I used typeover for actual content changes more than I realized and it’s driving me a little nuts. Could you give me any hints as to how I might modify Wrapster to use Cmd or Ctrl as a modifier key for those wraps (or all wraps, that’d be fine too)? I’m assuming I can’t specify a modifier key in the the WrapOptions.plist file.
Thanks for an awesome plugin, sorry to nag you about personal-preference-oriented tweaks.
September 21st, 2009 at 11:32 pm
I’m having problems getting wrapster to work, it’s not activated at all. I’m on the latest version of Coda and OS X.
I’m not sure if it was upgrading to snow leopard that broke it or something else. I tried re-installing the plugin. Thanks if anyone can help.