Dragging Address Book cards to TextMate

If you drag a card from your Address Book into a TextMate window, the vCard representation of that card will be pasted into the TM window. For example, the card for Apple in my Address Book pastes in like this:

BEGIN:VCARD
VERSION:3.0
N:;;;;
FN:Apple Computer Inc.
ORG:Apple Computer Inc.;
TEL;type=MAIN;type=pref:1-800-MY-APPLE
item1.ADR;type=WORK;type=pref:;;1 Infinite Loop;Cupertino;CA;95014;USA
item1.X-ABADR:us
item2.URL;type=pref:http\://www.apple.com
item2.X-ABLabel:_!<HomePage>!_
X-ABShowAs:COMPANY
X-ABUID:A1A2AA41-FA30-40AE-9925-FD6DB270B0A5\:ABPerson
END:VCARD

In the interests of space, I’ve removed the lines that store the picture of the Apple logo.

For reasons I hope to explain in a later post, I’m working on a project where I need to paste in just the name and a URL-escaped version of the Address Book ID (the X-ABUID line), like so:

Apple Computer Inc.:A1A2AA41-FA30-40AE-9925-FD6DB270B0A5%3AABPerson

(Digression: The ID is a unique code number that the Address Book generates for each of your cards. You probably have an Apple Computer card in your address book, but it would not necessarily have the same ID as mine.)

(Further digression: Notice that the “\:” in the X-ABUID line in the vCard has been turned into “%3A” in this line. There are two kinds of escaping involved in this. The actual ID is

A1A2AA41-FA30-40AE-9925-FD6DB270B0A5:ABPerson

which is what I would get if I asked AppleScript to give me the ID of the card. Since colons have special meaning in vCards, the colon near the end of the ID has to be escaped—and the vCard format uses backslashes for escaping. Colons are also special in URLs, but URLs use percent signs and ASCII codes (in hex) to escape special characters. So the colon becomes “%3A.”)

I could, of course, drag in the card and edit away the parts I don’t want; but because I’m lazy, I’d like that editing to be done for me automatically. So I wrote a TextMate drag command. Here’s what it looks like in the Bundle Editor (click on the image to see it full-sized).

As you can see, the command is called “vCard” and is linked to files with a “vcf” extension. This is the extension your vCard will get if you drag a card out of the Address Book and drop it into a Finder window or onto the Desktop. The TextMate manual describes drag commands only in the context of files being dragged into TM from the Finder, but it turns out that it will also accept a vCard dragged directly from the Address Book, which is very convenient.

The command itself is a short Python program.

 1:  #!/usr/bin/env python
 2:  from os import environ
 3:  from sys import stdout
 4:  
 5:  f = open(environ['TM_DROPPED_FILE'])
 6:  
 7:  if environ['TM_MODIFIER_FLAGS'] == 'OPTION':
 8:    info = []
 9:    for line in f:
10:      if line[:2] == 'FN':
11:        names = line[3:].strip().split()
12:        if names[0] in "Mr. Mrs. Ms. Dr.":
13:          del names[0]
14:        info.append(' '.join(names))
15:      if line[:7] == 'X-ABUID':
16:        info.append(line[8:].strip().replace('\:', '%3A'))
17:    print ':'.join(info)
18:  else:
19:    stdout.write(''.join(f))
20:  
21:  f.close()

Line 5 opens the vCard “file,” which is identified by the TM_DROPPED_FILE environment variable. What we do with the vCard depends on whether the user is holding down the Option key as he drops the vCard into the TM window. If the Option key isn’t down, then the full vCard is pasted in, as usual. This behavior is governed by the else clause on lines 18 and 19. I used stdout.write to do the printing because print puts an extra linefeed at the end.

More interesting is the behavior of the command when the Option key is held down. This is covered by lines 7-17. Basically, the script

  1. extracts the full name of the contact from the FN line,
  2. extracts the ID from the X-ABUID line, and
  3. sticks them together and prints out the result.

Since I didn’t want courtesy titles (Mr., Mrs. Ms., Dr.) showing up in the name, lines 12 and 13 look at the first word of the full name and delete it if it’s a title. The replace in line 16 turns the “\:” into “%3A” as discussed in the digression above. I used print to output this line because here I do want a linefeed at the end.

So now I can do a simple drag from the Address Book and get the full vCard as before, but I can also Option-drag the card to get this special behavior.

What’s the point of all this? Well, there’s a special URL type that the Mac uses to refer to a particular card in the Address Book. For my Apple Computer card, that URL would be

addressbook://A1A2AA41-FA30-40AE-9925-FD6DB270B0A5%3AABPerson

which is simply addressbook:// followed by the URL-escaped ID of the card. I can type

open addressbook://A1A2AA41-FA30-40AE-9925-FD6DB270B0A5%3AABPerson

in the Terminal, and the Address Book will open to the Apple Computer card. More interestingly, I can embed this link in a local HTML file,

<a href="addressbook://A1A2AA41-FA30-40AE-9925-FD6DB270B0A5%3AABPerson">Apple Computer Inc.</a>

and when I view that file in my browser, a click on the link will also open Address Book to the Apple Computer card.

My goal is to create local HTML files containing notes and other information associated with various projects at work. Included in these files will be the names of other people and businesses involved in the projects. Turning these names into links to their Address Book entries, will give one-click access to their full contact information from the browser. The particular form I’ve chosen for the Option-drag output makes it easy for me to generate these links automatically.

This command could, of course, be modified to paste in other information: name and address, name and telephone numbers, etc. This would involve more complicated parsing of the vCard data (vCards can have lots of escaped characters), and it would probably be wise to use a library like VObject.

Tags: