Umar Ahmad

Porting my blog to Hugo from inside Emacs

A few days ago I ported my blog to hugo. I did this mostly while staying inside Emacs and switching to the web browser every now and then.

Doing this required me to use Emacs to edit and manage multiple files at once and this post demonstrates a few of these techniques. The post is therefore mostly task agnostic and the techniques explained here should be usable for any such tasks.

This is in no way a comprehensive post for porting any blog to hugo and I've deliberately skipped steps that were either too straightforward to perform or used a technique that I've already covered in doing something else. For a more detailed understanding of the process, please refer to this blog post by someone else.

For the sake of brevity I’ll only cover these topics:

Setting up the environment

Hugo is a static site generator that works by converting the "content" files written in many of the formats it supports, such as markdown or org into a set of html files.

It uses a simple layout system mainly comprising of single pages and list pages to save the developer any repetitive work by reusing components across multiple places.

Installing hugo

system-packages package makes it possible to install any package from within emacs.

Pressing C-c P i bound to system-packages-install and typing hugo in the minibuffer installs it using your preferred package manager.

Setting up the directories and repositories

I planned on having two repositories for the blog. One would be the source repository having hugo files and the other would be for the generated html.

I usually do directory operations from inside dired but I feel counsel-find-file is more intuitive when creating new files, in different locations.

  • C-x C-f bound to counsel-find-file
  • Type in blog/blog-src followed by C-M-o
  • d to create a directory
  • Type in blog-gen and M-o then d again to create another directory and quit to ivy buffer

This is how it looks in practice:

Click here to download or view the video in a full browser window

Initializing repositories can be done via magit

  • C-x m bound to magit-status a directory will create a repository if one does not exist already and open magit-status buffer
  • M a from there adds a remote and fetches it
  • b c checkouts a new branch from another branch

After setting up the environment I can start porting my blog there.

Porting content files from old blog

Moving my files from octopress to hugo required a few minor transformations to happen.

  • 2014-02-19-hello-blogging.markdown to be renamed to
  • Adding aliases to maintain the older links working
  • Fixing invalid markdown that was valid in the older spec
  • Removing few unnecessary meta tags from the header files

These need to happen on every file.

Bulk renaming

dired-mode and wdired are great for such tasks. Wdired makes any directory list editable like any other file.

  • Opening the dired buffer and pressing W to switch to wdired
  • C-x h to select all the lines followed by C-n to limit it to the only files
  • C-S-c C-S-c bound to mc/edit-lines to get a cursor on every line.
  • Edit the files names accordingly and C-c C-c to save the changes to disk. This is how it looks in practice:

    Click here to download or view the video in a full browser window

Updating meta

aliases provide a way for hugo to create multiple links for one single post. The path for posts in my older blog was in year/month/day/blog-title format. There's a way to do this for all posts in hugo, but I only wanted to retain this format for the older posts and would be happy with /blog/blog-title format that hugo uses by default.

To do this I use the date field in the header of the octopress markdown files. These can be manipulated to create the date year/month/day/ part in the aliases field. The blog-title can be derived from the file name, by writing some lisp code and running eval-and-replace (custom function in my config). Macros can then be used to do the same for all the files

Macros in emacs allow an edit to replicated any number of times after recording them once. If we open the first file from dired, make the necessary changes and switch back to the dired buffer, we can make emacs do the change for all the files sequentially with just a single keystroke.

A demonstration may give a better idea

Click here to download or view the video in a full browser window

This can be followed by running C-c p s bound to projectile-save-project-buffers to save all the modified buffers

Fixing invalid spec

One of the few incompatibilities in the markdown spec was how markdown handled headings. Earlier


were considered valid markdown headings which now had to be changed to

# H1
## H2
### H3
#### H4

This again needs to be done across all the files.

Macros can be used here as well but macros can quickly get complex considering the keystrokes should be generic enough to work with all the files. I instead used a feature in emacs which allows me to search for terms from across multiple files and edit them in a single buffer, as if I'm editing a single file. Emacs can then cleverly apply those changes to the original files.

I did this by:

  • C-u C-c s s bound to counsel-rg to search through the current directory
  • C-c C-o bound to ivy-occur to get the search results in a buffer
  • w bound to ivy-wgrep-change-to-wgrep-mode makes the buffer editable
  • Editing them and running C-c C-c to save these changes

To keep this simple it is done twice once to remove the preceding # and once to remove the following #

This is how it looks:

Click here to download or view the video in a full browser window


These steps allowed me to have a working hugo blog with all the posts ported from the older blog system.

As I mentioned earlier, the purpose of this post was not to be a comprehensive guide of porting to hugo but instead a demonstration for how these tasks that might have required writing complex shell scripts or doing repetitive effort were done easily from within emacs.

Emacs provides other ways to manage multiple files together as well. Dired, LSP, Projectile can all be used to manage multiple files at once in ways not covered in this post and each demanding an article on it's own. I therefore, only covered the features that I used in this particular task.

My emacs configuration can be found on github for people who are interested in replicating some of the features described here.

#emacs #blog