Adding Emacs / PyBlosxom Support for a Custom Format

In PyBlosxom, blog entries are stored in regular files rather than in a database. This means that I can write my entries in Emacs (hurrah). PyBlosxom can handle posts in any format it has a parser for.

The simplest parser removes the metadata from the beginning of the file and passes the remainder of the file directly to the output webpage. Ergo, in the most simple format, the entries should be written in html (with a basic text header). More complicated parsers could be used for formats like xml or wiki markup. PyBlosxom uses a file’s file extension to determine what format the entry file is in.

For some unusual reason PyBlosxom associates the simple pass-through parser with .txt files (wouldn’t it make more sense to use .html?). In any case, I decided that I wanted to add my own file extension, .blog, so that I could easily distinguish my blog posts from other text files and html files on my system and so that my editor could treat the files specially.

The first step was to make PyBlosxom recognize the files as entries which it knows how to parse (anything PyBlosxom doesn’t have a parser for will simply be ignored).

On line 79 in pyblosxom.py, is a block of code which I modified as follows:

# entryparser callback is run here first to allow other plugins
# register what file extensions can be used
data['extensions'] = tools.run_callback("entryparser",
                {'txt': blosxom_entry_parser, 'blog': blosxom_entry_parser},
                mappingfunc=lambda x,y:y,
                defaultfunc=lambda x:x)

This is sufficient to make PyBlosxom treat .blog files just like .txt files.

The next step was to make the files easier for me to write. First off, Emacs should open the files in html-mode. Adding the following bit of code to my .emacs file accomplishes this task:

(add-to-list 'auto-mode-alist '("\\.blog\\'" . html-mode))

The next step requires a tiny bit of background information on the format of PyBlosxom entries. The basic format of a PyBlosxom entry looks like this:

Title Of Entry
#metadata-1 value-1
#metadata-2 value-2
(...)
#metadata-N value-N

Post line 1.
Post line 2.
(...)
Post line N.

Note: the blank line is not required, but it makes the file more (human-) readable.

I always use the same two metadata lines: #postdate (from my metadate.py), and tags (from Joe Topjian’s tags.py). Because of this there are a few lines which are similar across all of my blog posts. Why not have my editor enter these automagically, including entering the current #postdate (in the format YYYY-MM-DD HH:MM)? How convenient that Emacs provides a mechanism just for this purpose: skeletons.

I wrote the following code and added it to my .emacs file:

(define-skeleton blog-entry-skeleton
  "Inserts a PyBlosxom-style blog entry skeleton into the current buffer.
This only makes sense for empty buffers."
  "Title: "
  str | "Untitled Entry" \n
  "#postdate " (insert-date-and-time) \n
  "#tags " ("Enter a tag: " str ",") '(delete-backward-char 1) \n \n
  "<p>" _ "</p>")

When executed, this skeleton prompts the user for a title (if the user simply presses RET it defaults to Untitled Entry), repeatedly prompts the user for tags (keywords) (until the user simply presses RET), enters the current #postdate automatically, and the leaves the cursor inside a new <p>

The final touch is to make the skeleton automatically execute when a new .blog file is created:

(eval-after-load "autoinsert"
  '(add-to-list 'auto-insert-alist '("\\.blog\\'" . blog-entry-skeleton)))

It’s like magic!