April 11, 2011 at 10:18 PM by Dr. Drang
Last week I wrote a couple of small scripts for transforming TextExpander snippet abbreviations. Today I added another script to the repository on GitHub. This one, called teprefix, changes the abbreviation prefixes in a TextExpander library file (one with a
What’s an abbreviation prefix? Many TextExpander users put a 1-2 character “code” at the beginning of their snippets so they don’t get inadvertent snippet expansion when writing or programming. For example, I always start my snippets with a semicolon because it’s easy to type (right there on the home row) and there are no circumstances in which a semicolon should be immediately followed by an alphanumeric character. By designing my snippets this way, I don’t have to worry if my snippets use actual words. My
;furl snippet—which inserts the frontmost URL in my browser—will never be accidentally expanded when I’m writing about flag etiquette or sailing (it could happen).
It’s nice to be able to exchange
.textexpander files with other TE users, but it’s a pain to edit the snippets if the person you get a file from uses a different abbreviation prefix. That’s where teprefix comes in. It reads a
.textexpander file with someone else’s prefix and writes out a new
.textexpander file with your prefix. So if you use a pair of commas as your prefix, you could take my
URLs.textexpander file and make it your own by running
teprefix -o ';' -n ',,' URLs.textexpander
to get a
Here’s the source code:
python: 1: #!/usr/bin/python 2: # encoding: utf-8 3: 4: """ 5: Read a .textexpander snippet file and generate a new one with a different abbreviation prefix. 6: """ 7: 8: import plistlib 9: import sys 10: import os.path 11: import getopt 12: 13: usage = '''Usage: teprefix [options] tefile 14: 15: Create a new TextExpander file with different abbreviation prefixes. 16: 17: Options: 18: -o <old prefix> The old prefix, i.e., the one that's used in 19: --old=<old prefix> the existing TextExpander file. It's best 20: to enclose the prefix in single quotes to 21: avoid interpretation by the shell. Default is 22: the empty string. 23: 24: -n <new prefix> The new prefix, i.e., the one you want to use. 25: --n=<new prefix> Again, it's best to enclose the prefix in single 26: quotes to avoid interpretation by the shell. 27: Default is the empty string. 28: 29: -h, --help Show this usage message. 30: ''' 31: 32: # Get the arguments from the command line. 33: try: 34: optlist, args = getopt.getopt(sys.argv[1:], 'o:n:h', ['old=', 'new=', 'help']) 35: except getopt.GetoptError, err: 36: print str(err) 37: print usage 38: sys.exit(2) 39: 40: # Process the options. 41: oldprefix = ''; # default 42: newprefix = ''; # default 43: for o, a in optlist: 44: if o in ('-o', '--old'): 45: oldprefix = a 46: elif o in ('-n', '--new'): 47: newprefix = a 48: else: 49: print usage 50: sys.exit() 51: 52: # Extract folder and filename. 53: try: 54: infile = args 55: basename, extension = os.path.splitext(infile) 56: except IndexError: 57: print "No input filename." 58: print usage 59: sys.exit() 60: 61: # Make sure it's a TextExpander file. 62: if extension != '.textexpander': 63: print("%s is not a TextExpander file." % infile) 64: sys.exit(-1) 65: 66: # Generate the new filename. 67: outfile = basename + '-new.textexpander' 68: 69: # Parse the snippet file 70: try: 71: te = plistlib.readPlist(infile) 72: except IOError: 73: print("Couldn't open %s to read from." % infile) 74: sys.exit(-1) 75: 76: # Go through the snippets, replacing each oldprefix with newprefix. 77: for i in range(len(te['snippetsTE2'])): 78: prelength = len(oldprefix) 79: if te['snippetsTE2'][i]['abbreviation'][0:prelength] == oldprefix: 80: te['snippetsTE2'][i]['abbreviation'] = newprefix + \ 81: te['snippetsTE2'][i]['abbreviation'][prelength:] 82: 83: # Write out the new .textexpander file. 84: try: 85: plistlib.writePlist(te, outfile) 86: print "Wrote:", outfile 87: except IOError: 88: print "Couldn't write new textexpander file", outfile
One thing you may be wondering about is my choice of
getopt as the library for parsing the command line options; Python has two other libraries,
argparse, that are supposed to be improvements on
getopt. The problem is that
optparseis deprecated as of Python 2.7; and
argparseisn’t part of the Python 2.6 distribution, which is the distribution that comes with OS X.
Getopt is the only library that’s guaranteed to work now and for the foreseeable future. I’d be happy to switch to
argparse, but not until Apple puts 2.6 behind it. I’ve read that the Lion preview comes with 2.7, which is encouraging.