This has been updated
This blog is basically my labnotes where I explore different parts of technology. Almost all of my coding related activity starts off in this repo, while I explore different things to see how they work. I have a lot of things in drafts, and I wanted to learn how to build a simple emacs interface to let me navigate around my file system.
I couldn't find any good documentation on how to do anything with
tabulated-list-mode so I spend the evening poking around and seeing
how it works. Here you go.
The final file is blog.el
My basic directory structure
I have my repo checked out at
~/willschenk.com, and I put all my work
content/articles and then the year. So this file is called
org file is at the top level directory, and in the past
I wrote in
md files so I want to make sure that they come through as
The basic idea is that
- You create a derived mode from
- This defines the column headers in
tabulated-list-format, and some other stuff
You create a function that
- Creates a new buffer
- Switches to your derived mode
tabluated-list-entries, which is a list of lists, the first element being the key and the following elements are the data
(tabulated-list-print t)which displays the data
- You create a mode map that lets you add functions, the selected
keyis returned by
One tricky thing to figure out is how to create the data. It looks like
Which you can create using
(list key1 (vector col1 col2 col3)) if you
want to actually use the values that
col1 points to rather than the
col1 itself. Yay lisp!
Let's get started.
Looking at the front matter
This function takes a file, and passes it through
awk to parse the
front matter. We will basically call this 4 times for each file to
pull out the
Also, I'm removing any quotes around the results.
This takes a file, and pulls out the attributes. I'm assuming that the first ones it find is actually the top matter, we ignore all other matches other than the first.
Depending upon what sort of front matter you use, you may need to
adjust the regex. All my old markdown files are using
yaml and not
toml, so your mileage may vary.
Figure out if its a directory or not
For short posts that don't have any tangling or other sub objects, my
org files live in the year directory. For others, it's either going
index.org so if we get a directory lets see which
one is in there.
Figure out which parser to delegate to
Given a file name or a directory, figure out which parse method knows how to make sense of it.
Scan through all of the files and then parse them
I'm again shelling out to the
find command with
2 to give
me a list of the files and/or directories that contain blog posts.
For each of the files, I'm parsing them to get the data in tab form
that the mode knows how to deal with.
dolist was fun to figure out.
Set up the mode itself
We create a derived mode called
In it we set the columns, padding, sort order (on date) and
explicitely tell it to use our mode map,
blog-mode-map defined below.
It's unclear why it doesn't pick it up automatically, but I needed to
call it out specifically.
We also create a
blog-list function which is our entry point. This
creates and opens a new buffer, switches it to
blog-mode, loads in our
data, and then tells it to display.
tabulated-list-entries is local
to the buffer, by the by, so you can have multiple modes using the
Create the mode map
Here I'm defining some functions that are specific to our mode.
|Open the selected file|
|Only show drafts|
|Only show published posts|
|Show all posts|
|Create a new post|
|Start the hugo process|
For fun I also created a
transient popup which shows all of this.
I set the key to be the filename, so
(tabulated-list-get-id)) opens the file.
These functions filter the
blog-mode-entries variable to filter what
is displayed. I'm not sure how I feel about calling
tabulated-list-print each time but it seems to work.
Actions: create a new post
I like my urls to be the same as the title, so the first function here normalizes the title to fit in the filesystem. I've forgotten where I copied this code from, by thank you internet.
I have two types of posts. "mini" which just means its a standalone
file, and a full post, which is in a directory. I also turn on
org-babel-tangle on save, which I set as a local org
Action: Start hugo
This is probably too particular for my machine, since I run hugo
inside of a docker container so I need to start it with a script, but
this function starts hugo if it isn't running, then waits 5 seconds to
xdg-open to bring it up in the browser.
Plug it in
I couldn't find any good tutorials on how to write an emacs mode to interact with my system, so I thought I should write one. I think there's probably something on YouTube but it didn't show up in any search algorithms so hopefully this is helpful.