When I chose hosting and content management solutions for this website, I knew the blog portion would be the hardest. A bio page, a link to my GitHub profile, these are easy. But blogs are dynamic, and require much more background logic to manage. I made my hosting and content management decisions very deliberately, and I wanted to do a rundown of my setup in case anyone else finds it useful.
Emacs at the Center
Emacs is an interesting piece of software for its versatility. I've used it for Lisp development, playing music, chatting on IRC, and dozens of other needs.1 It's long been my LaTeX editor of choice, but I've also taken to using Org for more casual writing (e.g. "Hey Carl, can you give me your thoughts on this paper?"). Increasingly, Emacs has replaced more and more of my userspace, and doing any sort of real work outside of it is a major point of friction. I wasn't going to blog without it, so I needed a system that would let me work in plain text, ideally using Org as a markdown language. WordPress has caused me to lose patience with browser-based WYSIWYG editors.
I use several computers, and I value my time. I maintain my Emacs config across machines, but the last thing I'm looking for is to manually download unsupported tarballs and rejigger some Ruby blogging environment on each computer. The dream is that writing a new post entails opening Emacs, visiting a new Org file, and writing immediately. Visible PHP anywhere? Dealbreaker.
Cheap is good. Free (as in beer) is better. I already sprung for the Ascension Island vanity URL.
GitHub Pages is a slick way to use Jekyll, a snappy and beautiful static site generator, while abstracting away all of the nitty gritty. There's a large community around the product, which has led to the development of some wonderful starter kits that amount to:
- Fork the repo (I use Dean Attali's Beautiful Jekyll).
- Change Dean's name to yours.
- Add static pages, blog, create buttons to your GitHub or an RSS feed, it's yours now.
The entire site exists in a Git repository, making it incredibly portable, and builds happen from Emacs. If I want to edit it from a new machine, all I need to do is clone the repository! The whole setup is very off-the-shelf, which is exactly what I want.
GitHub Pages is free with limits I find acceptable. In particular, it's a strong fit if your bandwidth demands are "no one will read this but I could conceivably write something that Hacker News might like." My greatest complaint is what while custom domains are supported, they do not currently allow HTTPS, a decision I hope they will reevaluate. GitLab Pages is a similar offering with more features and flexibility, but I am not aware of a setup as painless as the above, as when I looked it required much more configuration.
Version Control (Magit)
Predictably, GitHub Pages usage revolves around Git. It's probably good practice for a personal website to live inside a version control system, preventing me from breaking anything too badly, and GitHub Pages makes it a prerequisite. Git is a scary piece of software, living in the terminal and having some admittedly abstruse commands, hence why GitHub puts so much effort into shiny desktop frontends. Magit is an Emacs interface for Git, and it's remarkably effective and simple. I hardly use any of its functionality, but for all my staging, pushing, and pulling needs, Magit makes it a few simple keypresses, being too convenient for me to bother learning Git from the command line. Hooray!
If you ask people what the killer feature of Emacs is, the two answers you'll hear most often are its hackability through Lisp and Org-mode. Some people live their lives out of Org files. Writing in Org is more quotidien.
This post is not a guide to Org. If you need a reference, the manual is excellent to brush up on lists or fontification or even TODO items. I'm just going to talk about some of the more intermediate functionality I use in this blog.
Exporting to Jekyll
Org-mode has robust exporting capabilities. And very thorough documentation, even for niche cases like this. While Jekyll expects HTML documents as its input, I'm writing in Org. Org-exports to HTML, but to run a blog requires slightly more work.
(setq org-publish-project-alist '(("carl.ac" ;; Path to org files. :base-directory "~/carldotac.github.io/org" :base-extension "org" ;; Path to Jekyll Posts :publishing-directory "~/carldotac.github.io/_posts/" :recursive t :publishing-function org-html-publish-to-html :headline-levels 4 :html-extension "html" :body-only t )))
Now Emacs will update the posts with
C-c-e P p.
Jekyll also expects files to be named in the form
The .html suffix is handled by the exporter, but I am proud to say I can handle writing the date all by myself.
Post metadata is fairly self-explanatory. Jekyll has a certain format, and I put a block like this at the top of each post so that Org will leave it alone in the export.
#+OPTIONS: toc:nil num:nil #+BEGIN_EXPORT html --- layout: post title: "Blogging with Emacs, Org, and GitHub Pages" permalink: /:title/ tags: [emacs] --- #+END_EXPORT
Org's support for code blocks is outstanding, with all the languages I'm ever going to use, but I don't need literate programming features here. I just want syntax highlighting, which requires blocks (and maybe also the htmlize package–if it's not working, install that). This
#+BEGIN_SRC R players <- read.csv("offensive_stats_2016.csv", header=TRUE, sep=",") #+END_SRC
players <- read.csv("offensive_stats_2016.csv", header=TRUE, sep=",")
Links and Images
Inserting a link is easy.
org-insert-link, which will ask for a link (which supports a number of protocols, not just http/https) and then the text to link.
If you're not into letting Emacs improve your workflow, the underlying syntax is as follows.
[[https://www.youtube.com/watch?v=gjHOtxCRhnw][Mattingly's finest hour]]
Images don't get a special function.
I could write one, and almost did to make a point after writing that previous sentence, but decided not to bother.
Images are inserted with a path in double brackets, and since I have an image directory under version control, I just need to insert the relative path.
So to show off my devilishly handsome mug, I invoke
counsel-find-file, navigate to the desired photo, and use a special function to insert the relative file path (I use the Ivy code, which does all the hard stuff to insert an image), and then
Org's table editor is excellent and I have a habit of inserting the plain text tables into emails and the like.2
It exports beautifully to HTML.
M-x org-table-create and then this
| Player | Games | fWAR | |--------------+-------+-------| | Babe Ruth | 2503 | 168.4 | | Barry Bonds | 2986 | 164.4 | | Willie Mays | 2992 | 149.9 | | Ty Cobb | 3035 | 149.3 | | Honus Wagner | 2792 | 138.1 |
turns into this.
When editing the tables, Org can automatically realign the plain text columns with
C-c-c, a nice quality-of-life function.
Footnotes: Not Just for Academic Papers!
I might3 abuse footnotes.
Why wouldn't I, when they're this easy?
C-c-x f creates a new footnote and the exported document will have links between the in-text number and the footnote content.
M-x org-footnote-renumber-fn:N can renumber and reorder your footnotes should you write out of order or add a new footnote between existing ones.
Despite the number of moving pieces here, this setup has an ideal balance of simplicity in both setup and use. Maintenance, including security, is completely hands off, writing posts with all sorts of content is painless thanks to Emacs integration. I hope to keep this setup for a long time, and I'm pleased to see how achievable that should be.