Integrating denote Filenames with Sphinx

denote basics

For an in-depth introduction to denote be sure to check out this video from Prot himself however, at the core of denote is the file-naming sheme:

<timestamp>--<title>__<tags>.ext

where

  • <timestamp> captures the date and time the file was created and doubles as the file’s unique identifier

  • <title> a lowercase - separated string which captures your traditional file name

  • <tags> (called keywords by denote) which is a _ separated string

As an example the filename for this blog post is 20250217T182726--denote-filenames-with-sphinx__blog_blogging_denote_emacs_sphinx.rst

The main benefit in naming your files in this way is that you can perform some fairly sophisticated queries across your files with simple text based searches.

reStructuredText and denote.el

While I don’t use Emacs all the time, I think it’s safe to say it’s my default editor when working on personal projects. So it would be nice to be able to make use of the utilities provided by the denote.el package when working on this site.

One of the main features provided by the package is to insert front matter into your notes corresponding to the information encoded in the filename and to keep the two in sync when either one changes.

denote.el has built in support for several markup formats however, the reStructuredText syntax used by Sphinx is not one of them. Of course, being an Emacs package this isn’t something that a few lines of lisp cannot solve!

What about Markdown?

Yes, both denote.el and Sphinx support Markdown however, I simply prefer reStructuredText 😅

emacs/init.el
(use-package denote
  :ensure t
  :hook ((dired-mode . denote-dired-mode))
  :config

  ;; Add reStructuredText support to denote
  (add-to-list 'denote-file-types `(rst
                                    :extension ".rst"
                                    :date-function denote-date-iso-8601
                                    :front-matter ":title: %s\n:date: %s\n:tags: %s\n:identifier: %s\n\n"
                                    :title-key-regexp "^:title:"
                                    :title-value-function identity
                                    :title-value-reverse-function denote-trim-whitespace
                                    :keywords-key-regexp "^:tags:"
                                    :keywords-value-function ,(lambda (ks) (string-join ks ", "))
                                    :keywords-value-reverse-function denote-extract-keywords-from-front-matter
                                    :link ":denote:link:`%2$s <%1$s>`"
                                    :link-in-context-regexp ,(concat ":denote:link:`.*?<\\(?1:" denote-id-regexp "\\)>`"))))

Which instructs denote to make use of reStructuredText’s field list syntax when inserting front matter.

It also instructs denote to use a role called denote:link when inserting a link to another note, but we’ll come back to that a bit later on.