GTD, HPDA, and text files, part 2

By the end of the last post, I had set up folder in my home directory called “gtd” that contained a file for each GTD context: work, home, car, etc. Each of these files was a plain text file divided into sections according to project, and within each project section were “Next actions” and “Waiting for” lists. I had set up my text editor, BBEdit, to move quickly from project to project and context to context. Left undone was the ability to print nicely formatted HPDA cards from these files.

As I mentioned in the last post, the files are formatted using Markdown, a plain-text formatting syntax developed by John Gruber. Markdown takes certain typographical clues from the text and converts it into HTML. For example, in this excerpt

Blog
----

Next actions:

* GTD HPDA printing and "one-big text file"
* Combining Markdown and ASCIIMathML 

the line of dashes under the word “Blog” indicates a level 2 header and the two lines that start with asterisks indicate two items in a bulleted list. Blank lines separate paragraphs. There’s a lot more to Markdown, as you can see from the syntax description, but this is most of what I need for my GTD lists. I like Markdown because, unlike HTML, LaTeX, or troff, its formatting codes are almost invisible. I use it for this blog and to keep project notes for work (the subject of a future blog post, I hope).

At first, I thought I would just use Markdown as one of BBEdit’s Unix Filters, then preview the resulting HTML in a browser and print onto index cards from the browser. It was pretty easy to work up a set of scripts and settings for this, but it didn’t make sense as a workflow. The point is not to view my next actions lists in my browser, the point is to print them out; intermediate steps are a waste.

So I came up with this:

  1. Format the file, or project section, as HTML using Markdown.
  2. Convert the HTML to PostScript using html2ps, a Perl program by Jan Kärrman.
  3. Pipe the resulting PostScript to my printer.

Since the printers I use at work and at home have PostScript interpreters built-in, they accept PostScript without complaint. If I had different printers, I’d need another step—probably involving Ghostscript—to process the PostScript into a form palatable to the printer.

Step 1 is handled by Markdown, but not by the Markdown.pl file as it comes from Gruber’s site. Because I want a single Unix Filter script, written in Perl, to handle all three steps of the conversion and printing, I need Markdown to be in the form of a Perl module, not a standalone program. No big deal. I cut lines 66 through 225 from the current version (1.01) of Markdown.pl and saved the result as Markdown.pm in the ~/Library/Application Support/BBEdit/Unix Support/Unix Filters folder. Here’s an excerpt of the result, showing the lines just above and below the cut:

# (see _ProcessListItems() for details):
my $g_list_level = 0;       # line 65 in original

# This is where I cut out the Blosxom, Movable Type,
# and command-line stuff.

sub Markdown {              # line 226 in original
#
# Main function. The order in which other subs are called here is
# essential. Link and image substitutions need to happen before

Step 2 will be handled by html2ps, using a special configuration file. After downloading html2ps and installing it in /usr/local/bin, I made the following configuration file:

/* Configuration file for html2ps. 
   Meant for printing out on index cards.
*/

@html2ps {
}

/* Standard style sheet definitions */
body    { font-family: Times;
          font-size: 10pt; }
H1, H2  { font-family: Helvetica;
          font-size: 12pt;
          font-weight: bold; }
@page   { size: 8.5in 11in;
          margin-left: 3in;
          margin-right: 3in;
          margin-top: .25in
          margin-bottom: 6.25in}

I called the file html2psrc-hpda and put it in the gtd folder along with the other GTD files. Jan Kärrman was very clever to make the format of his configuration file mimic that of a CSS file, something that his target audience would be quite familiar with. In fact, it is a CSS file with just a couple of additions. The @page section I’ve made is something of a trick: the page size is letter, but the margins force the printing to be restricted to an index-card-sized area at the top center of the page. This setting works for the way I feed my index cards into the printer using the multipurpose tray, which has centered guides.

index card in multipurpose tray

Step 3 is handled by the Unix “lpr” command. The PostScript from the previous step is piped to the command

lpr -o ManualFeed=True

which will let me feed my index cards into the printer as shown in the photo above.

All three steps are wrapped up in a single Perl script called “HPDAPrint.pl” kept in ~/Library/Application Support/BBEdit/Unix Support/Unix Filters:

#!/usr/bin/perl

# The print command to which the output is piped.
my $printer = "lpr -o ManualFeed=True";

# The top of the HTML document.
my $top = <<'TOP';
<html>
<head>
</head>
<body>
TOP

# The bottom of the HTML document.
my $bottom = <<BOTTOM;

</body>
</html>
BOTTOM

# Slurp in the text and filter it through Markdown.
my $original;
{
  local $/;
  $original = <>;
}
use Markdown;
my $middle = Markdown::Markdown($original);

# Put page break comments before each <h2> except the first. Have to
# insert the comments from back to front to keep the offsets correct.
my @offsets = ();
my $position;
while ($middle =~ m/<h2>/g) {
  unshift @offsets, pos($middle) - 4;   # collect in reverse order
}
pop @offsets;                           # get rid of last (first) one
for $position (@offsets) {
  substr($middle, $position, 0, "<!--NewPage-->\n");
}

# Form the HTML and send it through the pipeline.
my $html = $top . $middle . $bottom;
open OUT, "| /usr/local/bin/html2ps -f ~/gtd/html2psrc-hpda | $printer";
print OUT $html;

# Output the HTML.
print $html;

In summary, this script

  1. defines the top and bottom of the resulting HTML file (Markdown only creates HTML snippets),
  2. filters the input through Markdown,
  3. adds HTML comments at each <h2> header that html2ps will interpret as page break commands,
  4. concatenates the top, middle, and bottom into a full HTML page, and
  5. pipes the HTML through html2ps and lpr to print out the nicely-formatted cards.

Because it is a filter, it ought to spit something out, so the final line outputs the full HTML. BBEdit will replace the input, which could be the entire file or just the selection, with the HTML.

I control the whole thing with this AppleScript, called “Print as HPDA.scpt”:

tell application "BBEdit"
  if selection as text is "" then
    copy text of document 1
  else
    copy selection
  end if
  make new text document
  paste
  run unix filter "HD:Users:my-name:Library:Application 
     Support:BBEdit:Unix Support:Unix Filters:HPDAPrint.pl"
  close text document 1 saving no
end tell

It makes a copy of the file or selection and pastes it into a new document before running the HPDAPrint.pl filter. This makes the filter run on the copy and protects the original. Since I have no use for the HTML-ified version, it closes that document without saving.

Using this arrangement is much easier than describing it. If I want to print out a project section, I select it, choose “Print as HPDA” from BBEdit’s AppleScript menu, and walk over to the printer to feed it a card.

selecting a project section

The results are compact and good looking.

HPDA project card

If I want to print a card for more than one project, I just select the text of both projects before choosing “Print as HPDA.” And if I want to print cards for all the projects in that context, I don’t select anything before choosing “Print as HPDA.” The page break comments in the HTML cause each project to come out on its own card.

Well, that’s it. I’ve noticed that “here’s how I organize myself” pages often have an excruciating level of detail, and I’ve tried to follow that model.