Posts Tagged ‘productivity’
TextExpander abbreviation design
March 15th, 2010 at 12:17 pm
You’ve probably seen Merlin Mann’s little screencast about TextExpander 3. He does a nice job of showing dynamically what I tried to show statically in this post: TE3’s new feature that lets you define snippets with multiple fill-in-the-blank fields. Watching the video, I learned a couple of things about Merlin’s use of TextExpander:
- He has his abbreviations expanded immediately instead of using a delimiter.
- He uses simple abbreviations without any special characters.
Because I also have my abbreviations expanded immediately, I’m a bit surprised Merlin doesn’t use a “signal character” to distinguish his abbreviations. Let me explain what I do and why.
First, delimiters. TextExpander’s Preferences give you the option of expanding snippets as soon as you finish typing the abbreviation or waiting until you’ve typed a delimiter.

A delimiter is typically a “word-ending” character: a space, a tab, or any one of a number of punctuation marks.

The idea behind delimiters is to keep TextExpander from doing an expansion sooner than you want it to. For example, a natural abbreviation for “TextExpander” is “te,” but if you have that as your abbreviation and you use immediate expansion, you’d never be able to type a word like “tell”—as soon as you hit the “e,” TextExpander would do the expansion, and you’d end up with “TextExpanderll.” Using delimiters, the expansion will only occur when you type “te” as a separate word.
Unfortunately, forcing TextExpander to wait until a delimiter is typed isn’t a complete solution. Depending on context, “te” might make a great variable name, and if I wanted a program line like
te = sys.argv[2]
TextExpander would turn it into
TextExpander = sys.argv[2]
You can tell TextExpander not to expand abbreviations in certain applications, but that does me no good, as I write both regular text and programs in the same application. (At the beginning of Merlin’s screencast, you see that he uses “sdate” as one of his abbreviations. That’s an even better variable name than “te.”)
Also, I have TextExpander fix some of my common typos. I have an “hte” snippet that expands to “the.”1 By using immediate expansion instead of delimiters, that snippet works to correct “htere” and “hten” as well as “hte” itself.
So, since delimited expansion doesn’t get me what I want, I use immediate expansion and a trick. The trick is to always start my abbreviations with a semicolon. There are no situations in my writing or programming in which a semicolon will be followed by anything other than whitespace. In English, a semicolon is always followed by a space; and in programming it’s almost always a statement delimiter—illegal to use in a variable name. Yes, most languages allow you to squeeze statements together,
a=5;b=6;
but that’s not considered good style unless you’re doing a Perl one-liner on the command line. It’s not something that comes up in my programming.
The semicolon is the perfect special character for abbreviations not only because of its use in English and programming, but also because of its position on the keyboard. It’s one of the home keys and it doesn’t require a Shift. Typing it is almost effortless.
With my system, an abbreviation like ;te works perfectly, as do abbreviations like
;bill, which gives me the fill-in-the-blanks expansion I showed in my earlier post;apple, which expands2 to the Apple character, ;shift, which expands to the Shift key character, ⇧;times, which expands to the multiplication symbol, ×
These are, I think, the natural abbreviations to use, and because they are real words, they wouldn’t work as abbreviations if it weren’t for the leading semicolon.
I know I’m not the only one who does this. I’m pretty sure I once saw a Twitter exchange between Jason Snell and John Gruber in which they each learned that the other used leading semicolons. When I saw that, I knew I was in good company.
Sadly, the semicolon trick is a poor match for the iPhone version of TextExpander because the semicolon key isn’t on the iPhone’s main keyboard. The few snippets I have on the iPhone—mostly date and time stamps—use a trailing “z” to distinguish them from real words. It’s not as good as the semicolon trick, but it works with a limited number of snippets.
TextExpander 3
March 11th, 2010 at 10:59 pm
Smile On My Mac released a new version of TextExpander this week. It has some distinct improvements over the previous version and one disappointment.
TextExpander is a utility—it was a Preference Pane, but now it’s a regular application—that expands abbreviations automatically as you type. You define both the abbreviations and what they expand into to fit the type of writing you do. So if you do a lot of writing on, say, Castigliano’s Second Theorem, you could define an abbreviation like “c2t” that would expand out to the full expression. You can also define snippets (that’s what TextExpander calls its abbreviation/full expansion combinations) for the current date and time, as well as snippets that insert the output of AppleScripts or shell/Perl/Python/Ruby/etc. scripts. It’s a great utility, and I use it a lot.
(TextExpander is, I think, not quite as versatile as the snippet facility built in to TextMate, but it’s getting closer with every update. And it can be used in any application.)
The two big improvements in TextExpander 3 are multi-computer syncing of your snippet library via Dropbox and snippets with several fill-in-the-blank fields.
Syncing via Dropbox is pretty self-explanatory. If you work at more than one Mac, you can keep your snippet library in your Dropbox folder and it will automatically sync across your machines. I haven’t been able to test this, for reasons that I’ll explain later, but if it works it will remove one minor frustration: typing an abbreviation defined on your other computer and not seeing it expand.
Snippets with several fill-in-the-blank fields will be great for certain types of boilerplate text. When one of these snippets is triggered, it pops up a window with the text, and you fill in the empty fields, tabbing from one to the next as you type.

Earlier versions of TextExpander had a less useful version of this. You could create a snippet that put the cursor at a spot in the middle of the text after expansion; this gave you the effect of a single fill-in-the-blank field. Multiple fields will let you use a single snippet to the do the work that used to take several.
So I’m generally happy with the upgrade, but there is a sore point: TextExpander 3 requires Snow Leopard, and one of my computers is a iBook G4, and it can’t run Snow Leopard because it doesn’t have an Intel processor. I don’t know if the Smile On My Mac folks have been listening to Brent Simmons, but this restriction is very disappointing to me. I haven’t replaced the iBook with a newer MacBook because I like its form factor and much of what I do on it is text-based, which doesn’t need a lot of computing power. Now, the latest version of one of my workhorse utilities for text won’t run on it.
Of course, TextExpander 2.x still runs just fine on the iBook, so it’s not like I’ve lost anything. But I can’t take advantage of the Dropbox syncing if only one of my computers has that feature. And it’s really annoying to see this update sheet appear on a machine that can’t install the update.

That’s just rubbing it in.
Making a quick email list
February 18th, 2010 at 4:02 pm
I coach my younger son’s YMCA basketball team and use email to send updates and reminders to the other parents. Today my wife needed that list of addresses to coordinate an after-game dinner with the parents of a (friendly) rival team. My first thought was to export the list as a vCard file from my Address Book and email it to her, but importing that into her Address Book would have led to several duplicates and more work for her to weed them out. Also, she had no interest in the phone numbers and other contact information I have for some of these parents; she just wanted the email addresses.
So I went ahead and did the vCard export, and typed up this simple Python filter:
1: #!/usr/bin/python
2:
3: contacts = open('/Users/drang/Desktop/contacts.vcf')
4:
5: for line in contacts:
6: if line[:3] == 'FN:':
7: print line[3:],
8: if line[:6] == 'EMAIL;':
9: colon = line.find(':')
10: print line[colon+1:]
The name and path to the vCard file is in Line 3. I had the vCard file open in TextMate as I wrote the script. The lines with the important data looked like this:
FN:Ms. Laura Ipsum
EMAIL;type=INTERNET;type=HOME;type=pref:lipsum@gmail.com
Lines 5-10 were written with this format in mind. The output was a list of names and addresses
Ms. Laura Ipsum
lipsum@gmail.com
Ms. Dolores Amet
dolores@ametfamily.com
Ms. Elizabeth Consectetur
liz1729@aol.com
which I copied into a email to my wife. Five minutes of effort, maybe, with some interruptions.
I’m sure the script won’t handle every situation, but that’s OK. It was easy to write and it got me what I wanted quickly. I didn’t even save the script. I ran it within TextMate, using the Run Script command (⌘R) in the Python bundle. When I was done, I kept the script in an open window until I wrote this blog post around it.
PNotes
February 11th, 2010 at 10:35 pm
Here are a few miscellaneous paragraphs about my no-server personal wiki system.
I’m tired of calling it “my no-server personal wiki system.” From now on it’ll be called PNotes, which will at least save me some typing. Its GitHub repository will remain the same.
PNotes is missing two things most wikis have: a history of edits and a search field. But it’s easy to overcome both of these limitations.
When I need to create a set of notes for a new project, I copy the PNotes notes folder—my local version of what’s in the GitHub repository—to the new project’s folder and delete the .git subdirectory inside it. I then issue a
git init
command from within notes. This starts up a new git history that will focus not on the programming, which probably won’t change at all, but on the content files. From this point on, I use git add and git commit whenever I think it’s warranted. I’ve thought about putting git commit into the PNotes makefile, forcing a commit whenever I modify or make new HTML pages, but so far I haven’t done so. I prefer the freedom of committing only when I can think up a good commit comment.
Searching hasn’t been as big a deal as I first thought it would be. Normally, I know exactly which note page will have the information I’m looking for, and finding it is simply a matter of scrolling or using the browser’s Find command on that page. For those few occasions when I couldn’t remember where a piece of information is, I just opened a Terminal window in notes and used grep to find what I was looking for. This is not as smooth a solution as having a folder-wide search field available from the browser, but given the rarity of these searches, an in-browser solution just isn’t worth the effort.
One other thing I typically do when I create a new PNotes folder for a project: I replace the generic folder icon with a Moleskine notebook icon like one of these:
![]()
I found one of these, at a larger size, by doing a Google Image search and made the others by fiddling with the band color in Acorn. It’s nice to have the PNotes folder stand out.
A reminder on how to change the icon of a folder:
- Open the image you want to use and copy it to the clipboard.
- In the Finder, do a Get Info on the folder you want to change.
- Select the folder’s icon at the top of the Get Info window by clicking on it.
- Paste. The generic folder icon should be replaced by the image on the clipboard.
This post has turned out to be a bit more miscellaneous than I’d planned.
The no-server notes wiki
February 10th, 2010 at 4:32 pm
I’ve just pushed a new version of my unnamed no-server notes wiki to its GitHub repository. Notes can now be organized in subdirectories instead of all being at the top level. Here’s the README.
This is a no-server personal wiki system that I created to keep track of project notes for work. I’ve put it here because it may be useful to others.

Goals
This is what I want:
- A self-contained file or folder of files that includes everything needed to write and view the notes. I want it to be easy to copy from one computer to another and to archive to DVD. This eliminates most of the available wiki systems, which store everything in a central database.
- The notes themselves to be written in Markdown rather than some specialized wiki markup. I write everything in Markdown and don’t want to shift context when switching from notes to a report. In fact, I’d like to be able to copy directly from my notes—markup included—when writing a report.
- To write the notes in my text editor of choice rather than in an HTML text input box or a word processor. Currently, that editor is TextMate, but TextMate itself isn’t the point. The point is to take advantage of the comfort I feel working in my normal editor. There’s a reason old Unix hackers like to do everything in Emacs or vi; it’s just more efficient to do all your text work in one environment.
- To be able to change the visual style of the notes as my needs or tastes change.
- To create new notes quickly and easily.
Requirements
Apart from what’s in the repository, you’ll need
- Python. The two build scripts,
buildPage.pyandbuildNotesList.py, are written in Python. - GNU make. The build scripts are controlled by a makefile.
- A Markdown processor. I use a self-customized version of Fletcher Penney’s MultiMarkdown. Whatever you use, you’ll have to provide the name of that command on Line 16 of
buildPage.py. - A SmartyPants processor. I use Gruber’s SmartyPants. Again, you’ll have to provide the name of that command on Line 16 of
buildPage.py.
If you need to include mathematical formulas in your notes, you should consider installing Davide Cervone’s jsMath. Once you’ve installed it, you can activate jsMath in the notes by uncommenting Line 10 of the header.tmpl file and adjusting the jsmathpath variable in the project.info file to point to jsMath’s easy.js file.
File structure
The top level of the notes directory contains all the support files, that is, all the files that are distinct from the notes themselves. These files are:
header.tmpl, the HTML template file with all the common code above the content.footer.tmpl, the HTML template file with all the common code below the content.project.info, a file of project-specific data, including the project name and number, the list of contacts (including links to Address Book entries if you’re on a Mac), and thefile://URI for the top-level directory.notes.css, the style file for browsing.notes-print.css, the style file for printing.styleLineNumbers.js, a pair of JavaScript functions that improve the formatting of source code.buildPage.py, a Python script that combines a Markdown input file with the template files and produces a single HTML file.buildNotesList.py, a Python script that searches the directory (and subdirectories) for notes files and generates a list of links to all the notes for display in the sidebar.Makefile, the makefile that controls the build scripts.
Notes files contain the actual content. These files should all have the extension .md and can be in both the top-level directory and in subdirectories. Two sample notes files are included: aa-overview.md in the top-level directory, and testing1.md in the Lab subdirectory.
Creating notes
As mentioned above, notes are just plain text files written in Markdown and saved with an .md extension. The first line will be the note’s title and will appear in the sidebar.

I use ATX-style headers, with hash marks indicating the header level, and I start each file with a first-level header, like this:
# Overview #
The build system is smart enough to get rid of the hash marks when making up the sidebar.
Notes files in subdirectories appear with greater indentation under the name of the directory—like an outline. Within each directory, the notes are ordered alphabetically according to their file names, so you can rearrange the order in which the notes appear in the sidebar by changing the file names without changing their content. At present, there’s no way to change the order of the subdirectories.
Executing make from the top-level directory will generate all the HTML pages, which can be opened with any browser. Subsequent executions of make will generate only those pages whose .md files are new or have been modified. Executing make clean will erase all the HTML files, but will not touch the .md files.
Editing notes
You can, of course, open any .md file in any text editor to make changes. If you’re using TextMate on a Mac, there’s a faster way: click the Edit in TextMate link in the side bar to instantly open the .md file in TextMate—no need to switch to the Finder, open the folder, and double-click the file icon. If you’re a BBEdit user, you can do the same thing, but you’ll probably want to change the name of the link. It’s on Line 33 of header.tmpl.
More details
I wrote a three-part series of blog posts describing this system and its scripts, here, here, and here. The scripts have changed since then, but the basic ideas are the same.
License
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported License. Do what you want with it, but provide a link back to either my blog posts or to my repository.
A new pocket pen
February 6th, 2010 at 1:02 pm
This morning I dropped our van off for a brake job and was killing time at a nearby Staples while my wife came to pick me up. While I was there, I found these house brand mini gel pens (item #636172) and picked up a box of twelve for about $5.

When closed, the pen is about the same length as a Fisher Space Pen, which is a convenient size for keeping in my pocket. When open, it’s a little shorter than the Fisher, but still easy to write with.

Why do I want to replace the Space Pen? Mainly because it doesn’t leave a smooth line. I’ve stuck with it because of its size and because its ink doesn’t smear. Generally, I prefer gel pens like the Pilot G2, but
- Their ink is a little smeary, which isn’t a big deal in the office, but can be a real pain out in the field.
- Their mini pens are hard to find nowadays.
The Staples pen leaves a smooth line that dries instantly on the paper I typically use. I can run my finger across something I’ve just written and get no smearing whatsoever.
Another advantage of the Staples pen over the Fisher is pocket clip. I doubt I’ll be cliping it in my pocket very often, but it will keep the pen from rolling off slanted surfaces, a constant problem with the Fisher.
The biggest downside of the Staples pens is that they feel cheap—mainly because they are. At least I won’t worry much about losing them. If I remember right, the Space Pen cost as much as four dozen of these.
More Avery labels
February 4th, 2010 at 4:02 pm
This week I had to create lots of small labels to attach to laboratory samples. To make this easier, I modified my file folder label script to handle the smaller Avery 5167 labels, the kind usually thought of as return address labels.
The new program, called ptlabels (“print tiny labels”), follows the same logic as the old one and uses the same command-line options. You can tell it which row and column to start on through the -r and -c options. The input format is also the same:
- Individual labels are separated by a blank line.
- Header lines, which get printed in bold, are designated by a leading hash mark.
- Header lines can have a left-justified and right-justified part; they’re separated by a vertical bar.
- Headers apply to all subsequent labels until a new header line is encountered.
As an example, this input
#Lorem project|1234
Sample 1
Sample 2
Sample 3
Sample 4
Sample 5
Sample 6
Sample 7
Sample 8
#Dolor project|9876
Sample 1
Sample 2
Sample 3
Sample 4
passed to
ptlist -r 3 -c 2
generates this output

As with the file folder label script, I find it easiest to run the script in TextMate via Filter Through Command… (⌥⌘R).

The script is in Perl, because that was my main language back when I wrote the original version. Rewriting in from scratch in Python would have been a waste of time.
1: #!/usr/bin/perl
2:
3: use Getopt::Std;
4:
5: # Usage/help message.
6: $usage = <<USAGE;
7: Usage: ptlabels [options] [filename]
8: Print tiny labels on Avery 5167 sheets
9:
10: -r m : start at row m (range: 1..20; default: 1)
11: -c n : start at column n (range 1..4; default: 1)
12: -h : print this message
13:
14: If no filename is given, use STDIN. A label entry is a plain text
15: series of non-blank lines. Blank lines separate entries.
16:
17: The first line of an entry is special. If it starts with a #, then it's
18: considered a header line. Everything in the header line up to the | is
19: printed flush left in bold and everything after the | is printed flush
20: right in bold. Subsequent lines are printed centered in normal weight.
21: If the first line of an entry doesn't start with #, it uses the header
22: of the previous entry.
23: USAGE
24:
25: # Set up geometry constants for Avery 5167.
26: $topmargin = 0.55;
27: $pocol[1] = 0.45;
28: $pocol[2] = 2.50;
29: $pocol[3] = 4.55;
30: $pocol[4] = 6.60;
31: $lheight = 0.50;
32:
33: # get starting point from command line if present
34: getopts('hr:c:', \%opt);
35: die $usage if ($opt{h});
36:
37: $row = int($opt{r}) || 1; # chop off any fractional parts and
38: $col = int($opt{c}) || 1;
39:
40: # Bail out if position options are out of bounds
41: die $usage unless (($row >= 1 and $row <= 20) and
42: ($col >= 1 and $col <= 4));
43:
44: # Set initial horizontal and vertical positions.
45: $po = $pocol[$col];
46: $sp = ($topmargin + ($row - 1)*$lheight);
47:
48: # Pipe output through groff to printer (manual feed).
49: open OUT, "| groff | lpr -o ManualFeed=True";
50: # Change to PDF before sending to printer.
51: # open OUT, "| groff | ps2pdf - - | lpr -o ManualFeed=True";
52: # Preview output instead of printing directly.
53: # open OUT, "| groff | ps2pdf - - | open -a /Applications/Preview.app";
54: # Print raw troff code for debugging.
55: # open OUT, "> labels.rf";
56: select OUT;
57:
58: # Set up document.
59: print <<SETUP;
60: .vs 12
61: .nf
62: .ll 1.50i
63: .ta 1.50iR
64:
65: SETUP
66:
67: # The troff code for formatting a single entry, with placeholders for
68: # positioning on the page. The magic numbers embedded in the formatting
69: # commands make the layout look nice.
70: $label = <<ENTRY;
71: .sp |%.2fi
72: .po %.2fi
73: .ps 10
74: .ft HB
75: %s
76: .ps 10
77: .ft H
78: .ce 2
79: %s
80: .ce 0
81: ENTRY
82:
83: # Slurp all the input into an array of entries.
84: $/ = "";
85: @entries = <>;
86:
87: $bp = 0; # we don't want to start with a page break
88:
89: foreach $body (@entries) {
90: # Parse and transform the header and body.
91: if ($body =~ /^#/) { # it's a header line
92: ($header, $body) = split(/\n/, $body, 2);
93: $header = substr($header, 1);
94: $header =~ s/\|/\t/;
95: }
96: $body =~ s/\s+$//;
97:
98: # Break page if we ran off the end.
99: if ($bp) {
100: print "\n.bp\n"; # issue the page break command
101: $bp = 0; # reset flag
102: }
103:
104: # Print the label.
105: printf $label, $sp, $po, $header, $body;
106:
107: # Now we set up for the next entry.
108: $col = ($col % 4) + 1; # step to next column
109: $po = $pocol[$col];
110: if ($col == 1) { # we just went down a row
111: $row++;
112: if ($row > 20) { # we just went off the bottom
113: $bp = 1; # start a new page
114: $row = 1; # at the top
115: }
116: $sp = ($topmargin + ($row - 1)*$lheight);
117: }
118: }
The geometry constants in Lines 26-31 were initially set by making measurements of the labels and then adjusted through trial and error until the printing was nicely aligned with the die cuts on the label sheets. The final values are based not only on the sheet geometry, but also on how the labels pass through my printer via the manual feed slot. For good alignment on another printer, the values might need adjusting by a few hundredths.
Line 49 was also written with my default printer in mind. Because it’s a PostScript printer, I can take the PostScript output directly from groff and pipe it to lpr—no need to convert it first to PDF and no need to use lpr’s -P option to tell it which printer to use. (The -o option should be self-explanatory.)
Line 51 (commented out) is an example of what you may need to do if you don’t have a PostScript printer.
51: # open OUT, "| groff | ps2pdf - - | lpr -o ManualFeed=True";
Ps2pdf is part of Ghostscript, an open source suite of PostScript utilities that doesn’t come with OS X, but which I find invaluable. The two hyphens after ps2pdf tell it to use standard input and output instead of files on disk.
A more Mac-like possibility is shown in Line 53:
53: # open OUT, "| groff | ps2pdf - - | open -a /Applications/Preview.app";
This generates the PDF and opens it in Preview so you can see it before printing. I’m a wild and impetuous sort of guy, so I just send it off the printer and let the ink fall where it may.
My script hall of fame
January 27th, 2010 at 1:25 pm
Many of my posts here have been about the writing—or rewriting or rerewriting—of scripts to automate the dull, repetitive, clicky-click tasks so common to computer use. While almost all of these scripts have been worthwhile, a few have proved so useful that I use them on a weekly or even daily basis. These are the member of my personal scripting hall of fame.
Folder labels
I like the project file folders in my office to have crisp laser-printed labels. There are plenty of templates out there for Avery labels and their clones, but they’re usually made for MS Word or some other program I don’t use. Also, there’s a lot of repetitive typing associated with those templates, and I obviously want to avoid that. So I wrote a script called pflabels that takes plain text input in a simple format and generates output for printing on a sheet of 1″×4″ labels (Avery 5261 or the equivalent).

The input looks like this:
#Kernighan Building|4215
Drawings
Contract
Correspondence
Photographs and
videotape
#Ossanna Residence|4332
Report
Correspondence
The headings, which have the project name and number separated by the pipe character (|), are denoted with an initial hash symbol (#), and individual labels are separated by blank lines. If I’m going to make several labels for the same project (which is usually the case), I need only enter the heading once. The script takes two options, -r and -c, which tell it which row and column to start on, so it can print on label sheets that have been partially used.
I generally type up my label input in TextMate and then run pflabels on that input via the Text>Filter Through Command… (⌥⌘R) command.
Screenshot uploader
This script, called snapftp:
- Takes a snapshot of some portion of my computer screen.
- Names it.
- (Optionally) resizes it.
- (Optionally) uploads it to my blog.
- Puts the URL of the uploaded image on the clipboard for pasting into a post.
I’ve configured FastScripts to run snapftp with the ⌃⌥⌘4 key combination, a minor variation on the Apple-standard ⌘⇧4 key combo.

There are certainly commercial products that do some or all of these things, but none are so perfectly tuned to my way of working. I can’t imagine going back to writing posts like this without it.
Markdown links in TextMate
I write almost everything in Markdown, mainly because I can forget about the formatting and just type, but also because it’s so easy to read. To keep the visual clutter to an absolute minimum, I use reference-style links, which puts all the URLs at the bottom of the document, out of the flow of the text.

I use three TextMate command/snippet/macros to do this:
- One for inserting links as I type, triggered by ⌃L.
- One for inserting links after I’ve already typed out the text, triggered by ⌃⌥L.
- One for inserting Google’s I Feel Lucky link on text already typed, triggered by ⌃⌥⇧L.
The first two are described here, and the third is described here. They’re a bit complicated to set up but are wonderfully simple to use. I should probably turn them into a Bundle for easier installation.
URL getters for TextExpander
This started out as a set of scripts for getting the URL (or a shortened version of the URL) of the page showing on the visible tab of the frontmost Safari window, and the scripts were triggered by key combinations defined in FastScripts. Then, after seeing this tip by Jeff Gamet, I turned them into a set of TypeIt4Me snippets. When I switched from TypeIt4Me to TextExpander, I moved the snippet over and that’s what I use today.
The two workhorses are:
- The snippet triggered by
;furl, which gets the aforementioned URL and inserts it. - The snippet triggered by
;surl, which gets the URL, shortens it through the Metamark shortening service (run by perl.org), and inserts it.
I tend to use the first when writing posts like this or email and the second when using links on Twitter. The great advantage is that I can add a link to a page I’ve been reading without having to switch back to Safari to get it.
More recently, I added a few more snippets for getting the URLs of the first, second, third, and fourth Safari tabs, regardless of whether they are frontmost.
BBC Radio recording scripts for Audio Hijack Pro
These scripts, written in Python and AppleScript, differ from those described above in that I never actually run these scripts myself. They’re run automatically on a schedule set in Audio Hijack Pro, and they record and tag certain BBC Radio 2 shows and put them into my iTunes library for syncing with my iPod. In effect, they turn shows that aren’t podcasts into podcasts for me.
The scripts are described here and they’re also available in this GitHub repository.
Library loan tracking
This script, like the set of BBC scripts, is run automatically—in this case, by a launchd process. Every morning, it logs in to my local library and gathers information on all the items my family has checked out or on hold. It then sends that information to my wife and me in a nicely formatted email.

Now it’s true that my library emails us a notice shortly before an item is due, but the advantage of this system is that we see everything at once and can gather up all the books that will be due in the next several days before going to the library to make a return. And we don’t have to remember to sign on to the library’s web site; the information is delivered to us every day.
Suspend and sleep screen
This is a pretty recent script, but I’ve come to love it. Without logging me out, it suspends my user session and puts the display to sleep. Seeing the Desktop swing around in that cube animation (which I’ve been a fan of since Andy Hertzfeld used a simplified version of it in Switcher) has become the visual signal that my day at work is over.
Paper picking
January 18th, 2010 at 10:54 am
Last week a client sent me a bunch of paperwork to go through as part of an engineering analysis of a broken device. Part of the file was a photocopied product manual, the pages of which, unfortunately, had not been collated by the copy shop. So I had a run of odd-numbered pages, then a run of even-numbered pages, then another run of odds, another run of evens, and so on. The manual was a few hundred pages long—long enough to make the collation annoying but not so long that I felt justified in sending it out to a local print shop to do the job. I would be doing it myself.
I made an odd stack and an even stack and began the tedious process of putting the two together. The trick to making this go smoothly is to set up the stacks so that picking off individual sheets is easy. I’ve noticed, when seeing others sort through paper, that most people don’t know how to do this; there’s a lot of unnecessary (and unsanitary) wetting of fingers to try to keep from grabbing sheets two and three at a time. So I’m going to demonstrate how to avoid that. If I were 20 or 30 years younger, I’d probably call this a “lifehack,” which proves that there are some advantages to growing older.
The trick is to get the sheets offset a bit from one another so your thumb will touch only one sheet as you run it along the edge. Here are the four steps:
- Pinch the sheets together at one end.
- Bend the sheets, which will cause them to slide into a stairstep pattern at the other end.
- Pinch the other end while the sheets are still bent and release your pinch on the first end.
- Straighten the sheets, which will leave you with a stairstep pattern at both ends.


In these edge-view sketches, I’ve exaggerated how much the pages shift as you bend the sheaf. In reality, you’ll have to repeat the process a few times to get the offset big enough. When you’re done, the pages will be nicely arranged.

I’ve used this trick for sorting photos and card stock, too. Thicker sheets slide farther with each bend, but you have to be careful not to crease them.
As a structural engineer, I see the connection between this trick and the development of shear stresses in beams, but I’ve been nerdy enough for one post and won’t inflict that on you.
Why I won’t be switching to BusyCal
January 2nd, 2010 at 8:04 pm
After reading Wolf Rentzsch’s review of BusyCal (which I was led to my this Daring Fireball link), I decided to download it and give it quick test run. My initial impression is that its improvements over iCal aren’t enough to justify a switch.
Let me start by saying that BusyCal’s greatest strength—the ease with which it syncs with Google Calendar and with other BusyCals on your local network—are of little value to me. Apart from some very basic information, I don’t share calendars with co-workers (who run Windows, anyway), and my wife uses a paper calendar. Keeping my iPhone up-to-date is about all the syncing I need, so I’m not exactly a prime target for BusyCal.
But one thing in Rentzsch’s review caught my eye:
Simple text box for entering times. You can actually type out “4:23p” into a new event’s start time instead of navigating iCal’s awkward segregated time field.
Entering events in iCal has always been a pain because the hours and minutes are in different fields, forcing you to tab from one to the other. Simpler time entry would be a significant improvement.
What I learned from playing with BusyCal is that time entry is even better than Rentzsch’s description. Yes, you can type “4:23p” directly, but you can also type just “423p” and get the same result. And for an appointment at 3:00 PM, you can get by with typing just “3p.” This is so good it makes the multi-step procedure in iCal seem criminal.
Another nice thing about BusyCal is how it displays holidays in month view—with gray italic text down at the bottom of the day box.

Just like a nicely printed paper calendar. And you can designate any set of events as holidays, so family birthdays and anniversaries will get the same treatment as Christmas and New Year’s Day.
BusyCal also has preferences for showing weather forecasts and the phases of the moon. I particularly liked the way the full moon on New Year’s Eve was displayed in blue.
But there are some downsides. I agree with Rentzsch that weekends are kind of crappy looking. I don’t mind the red date numerals so much, but I really dislike the gray background; it makes reading the text on those days a bit harder and it diminishes the distinctiveness of the blue-gray “Today” background.
I was also disappointed to learn that, like iCal, BusyCal has only one preference setting for the starting day of the week. When I’m looking at a monthly view, I like seeing Sunday as the first day of the week, but when I’m looking at a weekly view, I prefer to start with Monday. This is the way most, if not all, paper calendars are laid out, and I can’t understand why this wouldn’t be an option in any professionally made calendar software. If BusyCal had that option, they might have made the sale.
I say “might” rather than “would” because it’s not clear to me how well BusyCal syncs with the iPhone. According to the BusyCal Configuration Guide, the syncing would have to be done through either MobileMe or Google Calendars. I have no interest in buying a MobileMe account, and my experiments with Google Sync in the past have been disasters. So I have to say that the lack of a direct sync with the iPhone is another mark against BusyCal.1
Update 1/3/10
I’m now pretty sure BusyCal will sync with the iPhone when the phone is docked. I added a test event via BusyCal, closed it, and launched iCal. The test event appeared in iCal, which suggests BusyCal is saving to iCal’s files, which will be synced when the iPhone is docked.
Because I’m not at my office computer (the one I sync my phone to), I can’t take the last step and see if the test event added in BusyCal gets put on the iPhone. I’ll give it a try tomorrow.
This test is more to satisfy my curiosity than anything else. Whatever the outcome, I won’t be switching to this version of BusyCal.
Update 1/4/10
OK, now I’ve run a sync test with my iPhone, and it’s clear that:
- BusyCal reads from and writes to the same calendar data files as iCal.
- Syncing my iPhone via the USB dock and iTunes works perfectly.
My syncing concerns in the paragraph above were, therefore, unfounded, and I’ve struck them out.
So it looks like I’ll be sticking with iCal and wearing out my tab key as I enter events. Too bad. There’s room for a high-end Mac calendar application.
-
I recognize that it isn’t BusyCal’s fault that it can’t sync directly to a docked iPhone; Apple keeps that syncing option to itself. But that recognition doesn’t make BusyCal’s syncing with my iPhone any easier.↩










