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, i.e., setting up the directory structure, git repositories and tooling.
- Port my markdown files so that they work with hugo
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 tocounsel-find-file
- Type in
blog/blog-src
followed byC-M-o
d
to create a directory- Type in
blog-gen
andM-o
thend
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 tomagit-status
a directory will create a repository if one does not exist already and open magit-status bufferM a
from there adds a remote and fetches itb 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 tohello-blogging.md
- 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 byC-n
to limit it to the only filesC-S-c C-S-c
bound tomc/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
#H1#
##H2##
###H3###
####H4####
#H1
##H2
###H3
####H4
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 tocounsel-rg
to search through the current directoryC-c C-o
bound toivy-occur
to get the search results in a bufferw
bound toivy-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
Conclusion
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.