Blogging in Org Mode
I recently transitioned from writing my posts directly in markdown to writing them in
org mode, a document authoring system built in GNU Emacs. I learned a lot in the
process, and also built a new org exporter in the process, ox-jekyll-lite
.1
Org Mode and the Meaning of Life
What is Org Mode?
Laozi said that the Tao that can be told is not the eternal Tao; I think we can safely
say the same of org mode. Org mode is many things to many people, but at it’s core it is
a tool for taking notes and organizing lists. Additional functionality allows for simple
text markup, links, inline images, rendered \(\LaTeX\) fragments, and so on. You can embed
and run code blocks within org files, using the powerful org-babel
package. Some
people have even written
their Ph.D. thesis in org mode. It’s an amazingly powerful tool, with a passionate
user base that is constantly expanding its capabilities.
Why Not Markdown?
I like to use org mode for my personal and professional note-taking because it has very good folding features - you can hide all headings besides the one you’re focusing on. You can even “narrow” your buffer, so that only the heading (“subtree”, in org-mode parlance) that you’re working on is present at all.
Org mode also has some nice visual features for writing, such as:
- rendering \(\LaTeX\) fragments inline
- styling bold, underlined, and italicized text properly
- excellent automatic formatting of tables
- code syntax highlighting in various languages
- display of images inline
I wrote in markdown (using markdown-mode
within emacs) for some time, but once I saw
what org mode had to offer, I realized that I needed to transfer my blogging over to
org. In particular, the Emacs mode markdown-mode
doesn’t have a lot of the features that
org mode does, such as inline rendering of math and images or well-built text folding. I
used org for notes, and I realized that it would be much easier to just write in org
instead of trying to get markdown mode to work the way I want it to.
Below is a short clip that shows just some of what org mode has to offer. You’ll want to full-screen it to make the text legible.
Overall, I find the experience of writing in org much more enjoyable than writing in markdown. Plus, I love hacking on emacs, and moving my blogging workflow over to org presented me with an opportunity to do just that! So of course, I couldn’t resist.
Org-Export and Jekyll
Blogging in Jekyll
The primary tool I use to generate my blog is a static-site generator called Jekyll, which is written in Ruby. I wrote a previous post describing my process for setting up my site. Pelican is a similar tool written in Python, and Hugo is a static-site generator written in Go. We’ll talk a bit more about Hugo later.
All of these tools allow the user to write content in simple markdown, with the site generator doing most of the heavy lifting in generating a full static site behind the scenes. In Jekyll, the user provided some basic configuration for each post, like a title, date, and excerpt, and then the them determines the details on how the text is rendered into fully styled HTML. I use the excellent minimal mistakes theme.
Unfortunately, markdown is not a nicely unified language specification There are many dialects of markdown, and each has subtle differences, so there is not, in general, one markdown specification to rule them all. For example, so-called “GitHub-flavored markdown”, which renders markdown from READMEs in GitHub repositories, has certian quirks that are not shared by the markdown I write for this site. To further complicate things, the static site generators often have their own quirks - Jekyll requires particularly-formatted front-matter to specify the configuration for each post, which is not part of the general markdown specification.
All that is to say, it wasn’t a trivial task to find something that converted org to the exact markdown that I need for my site. But before we jump into the details there, we should talk a bit about org exporters in general.
Org-Export
Org mode comes packaged with many built-in “exporters”, which convert from the org format to other text formats, including HTML, \(\LaTeX\), iCalendar, and more. It does come with a backend that converts org to markdown, which I hoped would be all that I need to convert org to markdown.
Unfortunately, the built-in ox-md
exporter doesn’t work very well, for a few reasons. It
falls back on using pure HTML (for example, to generate footnotes) when there are
markdown-native ways of accomplishing the same thing. Also, some things don’t work at
all - for example, equation exporting won’t work, since markdown requires you to enclose
LaTeX with \\[
and \\]
, whereas HTML only requires a single slash.2
A quick search will show that there are many tools built to address this problem. Org
exporter backends are designed to be easy to extend, and many users have extended the
markdown backend to work with specific static site generators. The most fully developed
of these is ox-hugo
, which is built to work with the site generator Hugo. This
package in particular would be a big source of the transcoding functions I would use,
but since it is built to be tightly integrated with Hugo, I couldn’t just use it out of
the box.
Elsa Gonsiorowski developed a Jekyll-friendly org exporter, called ox-jekyll-md
, which
provided the basis for what I would eventually build. She also wrote a blog post about
it - if you’re interested in customizing org exported, I’d recommend giving it a read.
Building ox-jekyll-lite
There are some things that ox-jekyll-md
does very well, including generating the
Jekyll-specific YAML front matter. However, I found that it lacks a few key features:
- handling footnotes in a markdown-native way
- rendering MathJax delimiters with double slashes (to make them markdown-compatable)
- exporting image links appropriately
- export link paths relative to the Jekyll root directory
Since these were essential to my blogging workflow, I forked that project and began work
on my org exporter, ox-jekyll-lite
.
Customizing an Org Export Backend
You can think of an org-export backend as a collection of rules for transforming org files into other text format. For example, how should underlined text be handled? How about code blocks? How about \(\LaTeX\) snippets? Each of these rules is encapsulated by a so-called “transcoding function.”
Org export backends are built to be highly extensible. If you extend ox-md
, for example,
then you “inherit” all the transcoding functions that it provides, and you can add or replace
only the functions you want to. For example, part of ox-jekyll-lite
looks like
(org-export-define-derived-backend 'jekyll 'md
:translate-alist
'((headline . org-jekyll-lite-headline-offset)
(inner-template . org-jekyll-lite-inner-template)))
This tells us that we’re defining a backend named jekyll
, which derives from the backend
named md
(which, if you look, itself derives from the html
backend).
In the code above, the translate-alist
indicates that this backend handles headline
objects via the org-jekyll-lite-headline-offset
method, and handles the inner-template
object via org-jekyll-lite-inner-template
. These functions take in org elements,
returning text that will get dumped into the export buffer.
The transcoding function org-jekyll-lite-underline
is a particularly simple example:
(defun org-jekyll-lite-underline (underline contents info)
"Transcode UNDERLINE from Org to Markdown.
CONTENTS is the text with underline markup. INFO is a plist
holding contextual information."
(format "<u>%s</u>" contents))
Extending a backend consists of figuring out which elements you want to handle via special logic, then writing the appropriate transcoding functions for each.
Implementation Details for ox-jekyll-lite
Most of the more complicated transcoding functions in ox-jekyll-lite
are not written by
me. They either come from ox-jekyll-md
, or from ox-hugo
. For example, I got the
transcoder for footnotes, and for \(\LaTeX\) snippets, from ox-hugo
.
The most interesting addition that I made was to render file links relative to the root
directory of Jekyll, when possible. For example, if you have an image in your
assets/images
folder, Jekyll wants you to link to it as /assets/images/kitties.jpg
, not
with the full path relative to the root directory of your computer’s filesystem.
However, when I use C-c C-l
(along with Helm) to add a link to an org file, it renders
the link with the absolute path.3 It’s important that the link is “correct” for my
machine, so that any images can render inline, and the links are clickable by me when
from my orgfile. But if the links are relative to my filesystem’s root in the markdown,
then they won’t work within the context of my site. So, we need to “fix” the links as we
export the post to markdown.
I don’t get too complicated here - I just have the user specify a custom variable
org-jekyll-project-root
, which then gets pulled off of the beginning of file paths when
it is present.
For example, on my machine, this repository is located at
~/code/jekyll/peterewills.github.io/
, and so if I link to the file
~/code/jekyll/peterewills.github.io/assets/images/kitties.jpg
in my org file,
ox-jekyll-lite
will, upon export, transform this to a link to /assets/images/kitties.jpg
in the markdown output. This approach is nice and simple, but it doesn’t handle relative
links, or the situation where you have multiple Jekyll projects.
Anyways, if you want to give it a try, you can clone it from GitHub and check it
out. You can just load it up and use C-c C-e j J
to export an org file to a markdown
buffer.
Finally, as a side note, I just have to give a shoutout to the excellent s.el
and
dash
, which makes working in elisp infinitely more pleasant. Many thanks to Magnar
Sveen for building such nice tools for us all to use.
My Blogging Workflow
Now, my workflow for writing a post is pretty simple.
- Have brilliant idea
- Make an org file in the
_posts
directory, named likeYYYY-MM-DD-post-name.org
- Write brilliant words/equations/cat pictures/etc.
- Export to markdown via
C-c C-e j j
- Commit & push to GitHub
- Profit!4
The only additional complication, compared to a pure-markdown workflow, is the addition of the export step; other than that, it’s identical. And now I can blog in wonderful, beautiful org mode instead of clunky markdown.
An important caveat for anyone using org and Jekyll; in order to not have Jekyll stumble
over the org artifacts, you should add *.org
and ltximg
to the list of excluded files in
your Jekyll _config.yml
. You can see mine on GitHub.
Conclusion
If you are just starting to blog, and you love org mode, I’d recommend using Hugo to
build your site, so that you can use the excellent ox-hugo
. It’s a truly org-centric
approach to building a static site, and it’s much more fully-featured than any of the
solutions I’ve found in Jekyll or Pelican.
But, you might want to use Jekyll, because it integrates automagically with GitHub
pages, or perhaps you just like some of the available themes or whatnot. If that’s the
case, then I think org-jekyll-lite
is a reasonable solution for writing your posts in
org. It’s lightweight, and you’ll probably have to tweak it to fit your particular
needs, but it’s small enough that modifying it shouldn’t be too hard. Also, you can
always submit an issue on GitHub and I’ll see if I can help you out.
I hope this post has inspired you to explore more in org mode! It’s a great tool for organizing notes, tracking agendas/calendars/TODO lists, and for general writing.5 Happy blogging, and may the org be with you!
-
As I explain later on, this tool was based on both
ox-jekyll-md
andox-hugo
. ↩ -
The double slash is required because markdown interprets the first slash as an escape character. ↩
-
You can see an example of adding a link to an image in the org-mode demo video linked above. ↩
-
This is actually a lie; I don’t make any money from this site. ↩
-
There’s also the entire subject of literate programming, in which code is interwoven with documentation, which I think is a really nice paradigm, and for which org is a natural fit. ↩
Comments