Endless Parentheses

Concise ramblings on Emacs productivity.

Support on Gratipay
profile for Malabarba on Stack Exchange

How I blog: One year of posts in a single org file

About the Blog post series

When this blog was conceived, I decided that I wanted it to be entirely contained in a single org file, and that this would also be my Emacs init file. On the blog’s very first post I explained how to implement the latter, an init file that also serves other purposes. Today, Endless Parentheses turns 1 year old, and it’s time to explain the former, how to turn a file into a blog.

As is usually the case with first birthdays, the child has no clue of what’s going on, and it’s really just an excuse to indulge the parents into praising themselves for keeping the kid alive 12 whole months. As such, this will not be a productive post. Expect no code snippets, no Emacs news, and no productivity tips, as I release myself from my usual shackles and go off on a tangent for a change. Still, just in case someone else likes the idea, I’ve pushed the code to Github.

Before anything else, it should go without saying that the content of the posts is written in org-mode. The engine I use for exporting is a large wrapper around ox-jekyll, and the posts are all pushed to Github and rendered by their built-in Jekyll support.

Why keep a blog in a single file?

First of all because org, once you learn its knobs and bobs, is just plain powerful. This is all the more true because the post contents are also in org format, so you’re effectively removing one layer of distance between you and the content. For example, if I want to reschedule a post, I just find it with C-c C-j and hit C-c C-s; whereas, if the posts were separate files, I’d have to find it in dired, then visit it, and then hit C-c C-s.

This is a small difference, but it applies all around. If I want to link to a previous post, I find it with C-c C-j and then move back with C-u C-SPC, all without leaving the buffer. When I look at the posts list, the tags are listed right beside the title, I don’t have to open a file to see them.

Now let me be honest with you. I didn’t predict these advantages before I started the blog, so it’s not why I chose this approach. Rather, it was linked to the fact that I wanted to blog about all these elisp snippets I had built over years and accumulated in my init file.

You see, if posts were separate files I would have to copy the snippets to a separate org file, and then write about them there, and then export them to Jekyll. In this scenario, I just know I would eventually change some snippet (a healthy init file is a fluid creature) and forget to update the corresponding org file, and the thought of leaving out-dated code lying around sent a chill through my spine. Not to mention, this whole flow of “init file → org post → jekyll post” has one layer too many for my taste, and redundancy is an evil I slay with a chainsaw.

How it works

First of all, here’s what I see when Emacs starts up.

init-org-1.png

If you read (and remember) the first post, you’ll know that the actual init file is composed of code blocks inside that init.el headline. Everything else is text. Also, notice that last SEQ_TODO header. It specifies that headlines in this file have three possible TODO states, TODO, READY and DONE.

init-org-meta-binds.png

Every post is marked with one of these states, and that is what defines them. TODO is something I plan on writing about; READY is, well, ready to publish; and DONE is published.

This three-states setup has several uses, mainly:

  • I can review my entire history and my future schedule with a custom agenda command, leveraging all the features of org-agenda.
  • Whenever I change a snippet, and the headline above it is marked DONE, I’m immediately reminded to update the post (as simple as C-c b). So I’ll never leave outdated code around.
  • When Monday arrives sooner than expected, and I didn’t write anything new, I can issue C-c / T READY and get an org-sparse-tree of all READY posts.

init-org-ready-state.png

See how practical that is? This file is not just the blog and the init file, it’s also the future posts queue and the “vague ideas” list. All without having to do manual maintenance. Of course, the headline is automatically marked DONE when posted.

Then there are a few more advantages that arise simply from the fact we’re using org-mode.

  • I can physically move posts around with M-up/down and M-S-right/left, to whatever order makes more sense, instead of being constrained by alphabetical or historical order of files.
  • By nesting several posts under a headline, any tags or properties applied to the parent are inherited by the posts. (Killing redundancy, remember?)

    init-org-news.png

  • The C-c C-j (org-goto) command makes it a breeze to jump around.
  • It feels more Emacsy than anything else you could possibly do.

Last, but not least

This part applies to any of the org blogging methods (not just my setup), but still, the org-export engine is extensive and even more so if you know where to hack it (org links, in particular, are extremely versatile).

With a single C-c b, Emacs will spell-check the contents, export to Jekyll, clean up some links, move the file to the right directory, bring up magit-status, and even save a commit message to the kill-ring. You could even have it commit and push automatically too, if you’re a bit of a thrill seeker.

Good night, and thanks for coming

Well, now that I’ve finished monologuing, the cake is completely gone, there’s more candy on the floor than on the tables, and I think I hear a child crying somewhere, so it’s clearly time to wind down the party. Thanks for reading, and I mean that generally. Thanks for commenting too. Thanks for the emails and the tweets. Thanks for the bug reports and the pull requests, and any other form of positive interaction. This was a fun year.

Oh, and thanks for coming to the party. Little EP totally didn’t notice that you didn’t bring a gift. (Though he might notice next year… just saying.)

Tags: org-mode, blog, emacs

Support on Gratipay
comments powered by Disqus