This project was initially devised by the author to replicate a Zettelkasten workflow implementing Folgezettel using denote.el. It is intended to sit atop one’s usage of denote.el
. The only assumption is that note signatures be used as folgezettel index numberings in subdirectories within the user’s Zettelkasten[fn:1].
The vision of this package is to represent the folgezettel index in a list format (tabulated-list-mode
) and be able to navigate the index according to the numbering of notes, filter the shown notes arbitrarily (including by parents and siblings of a folgezettel index numbering), and automatically set the index numbering of a new note by the user’s selection of the parent folgezettel note[fn:2]. In a way, this is an attempt at reducing the gap in navigating a digital versus analog/physical Zettelkasten.
The current iteration of this package is somewhat clunky at places: bindings could be improved and the UX can be improved. However, I personally used this project as the sole entry-point to my Zettelkasten for months and at the very least it was enough.
- List notes in
tabulated-list-mode
buffer - Implements a basic cache to speed of displaying and sorting-by-index-number of notes
- Filter by subdirectory
- Filtering any column by arbitrary string using
tablist.el
- Sorting by folgezettel index numbering
- Navigation by index numbering
- Commands to conveniently set index number of note by selecting “parent” folgezettel note
Currently, this project is not available in a package repository. As such, users will need to manually download the files (e.g. git clone https://github.com/krisbalintona/denote-zettel-interface.git
) and ensure its dependencies are installed. Currently, these are the only third-party dependencies:
- Denote.el
- Tablist.el (used for filtering
tabulated-list-mode
entries)
Users can either evaluate something like this to install:
(use-package tablist
:ensure t)
(use-package denote-zettel-interface
:load-path "/home/USER/PATH/TO/LOCAL/REPOSITORY")
Or, if using Emacs-30 or newer:
(use-package denote-zettel-interface
:ensure t
:vc ( :url "https://github.com/krisbalintona/denote-zettel-interface.git"
:rev :newest))
Here is a varianet of the author’s use-package configuration:
(use-package denote-zettel-interface
:after denote
:vc ( :url "https://github.com/krisbalintona/denote-zettel-interface.git"
:rev :newest)
:autoload denote-zettel-interface--signature-lessp
:bind (("C-c n m" . denote-zettel-interface-list)
("C-c n r" . denote-zettel-interface-set-signature-list)
("C-c n R" . denote-zettel-interface-set-signature-minibuffer))
:custom
(denote-zettel-interface-signature-column-width
(+ 6 (cl-loop for file in (denote-directory-files)
maximize (length (denote-retrieve-filename-signature file)))))
(denote-zettel-interface-title-column-width 120)
(denote-zettel-interface-starting-filter-presets
;; I have a "zettels" subdirectory that contains all my "main notes." I also
;; have a "bib" subdirectory that contains my org files pertaining to books,
;; videos, papers, articles, and so on.
'("zettels/[^z-a]*" "bib/[^z-a]*"))
(denote-zettel-interface-starting-filter "zettels/[^z-a]*")
:init
(with-eval-after-load 'denote
(setopt denote-sort-signature-comparison-function #'denote-zettel-interface--signature-lessp)))
- Call
M-x denote-zettel-interface-list
to list Denote notes. - Press
/ d
(orM-x denote-zettel-interface-edit-filter
) to filter your notes by regexp on denote file names. - Use
M-N, =M-P
,M-n
,M-p
,M-d
, andM-u
to navigate notes shown by way of their index numbering. - Create a new note.
- In that note’s buffer, call =M-x denote-zettel-interface-set-signature-list=[fn:3] or =M-x denote-zettel-interface-set-signature-minibuffer=[fn:4] to interactively select a folgezettel parent for that note.
- That note is now a child of the chosen parent note, with an index numbering that is automatically set to the next available index numbering for children of the parent note.
Below are a list of useful commands for those viewing the package for the first time. You can also find these commands and more via M-x apropos-command denote-zettel-interface RET
.
denote-zettel-interface-list
Display list of Denote files in variabledenote-directory
.denote-zettel-interface-display-note
Just display the current note in another window.denote-zettel-interface-edit-filter
Edit the currently existing filter.denote-zettel-interface-filter-backward
Filter the buffer to the next set of notes of the same level.denote-zettel-interface-filter-forward
Filter the buffer to the next set of notes of the same level.denote-zettel-interface-filter-down
Filter the buffer to the children of the current note.denote-zettel-interface-filter-up
Filter the buffer to the parent of the current note and its children.denote-zettel-interface-filter-top-level-next
Filter the buffer to the next index top-level notes.denote-zettel-interface-filter-top-level-previous
Filter the buffer to the next index top-level notes.denote-zettel-interface-goto-note
Jump to the note corresponding to the entry at point.denote-zettel-interface-goto-note-other-window
Open in another window the note corresponding to the entry at point.denote-zettel-interface-set-signature
Set the note at point’s (in `denote-zettel-interface’ buffer) signature.denote-zettel-interface-set-signature-list
Set the note at point’s signature by selecting another note.denote-zettel-interface-set-signature-minibuffer
Set the note at point’s signature by selecting another note.denote-zettel-interface-store-link
Call `org-store-link’ on the entry at point if an org file.
This project assumes the following folgezettel index numbering schema:
- Denote note signatures contain just the index numbering for that note.
- They are in a format like “1=3a12c1”. That is:
- The beginning of the index numbering begins with a positive integer.
- At any point, a “=” demarcates a new section of the index numbering.[fn:5]
- In portions of the index numbering which are not demarcated into sections by “=” are demarcated by alternating between numbers in digits.[fn:6]
- In a
denote-zettel-interface-mode
buffer, the “=” in these index numberings are rendered as periods. So: “1=3a12c1” becomes “1.3a12c1”.
I initially used denote-menu to navigate my denote notes, but found that if I used folgezettel, I needed a much more specialized package for navigating the index and setting new index numberings. Thus, this project was born.
The author of this project has migrated to org-roam
. Consequently, this project is no longer being actively developed. I am, however, open to making minor improvements to the existing functionality per the request of interested users.
To those interested, the author has moved to creating a similar package for org-roam
that is meant to achieve the same purpose of ndenote-zettel-interface
to an even greater degree: krisbalintona/org-roam-folgezettel.
Consequently, users are encouraged to either:
- fork this project and copy its code for their own purposes, or
- take inspiration from the functionality herein to further their own Zettelkasten workflow or develop their own project that improves upon those concepts.
[fn:1] In fact, users can treat separate subdirectories as different Zettelkastens, each having their own index numbering.
[fn:2] That is, if I have a new note and set its parent to a note whose index is “1=3a”, then it will automatically be numbered as “1=3a2” if “1=3a1” is taken.
[fn:3] This command produces a special denote-zettel-interface-mode
buffer where RET
will specially select the note at point as the folgezettel parent.
[fn:4] This command creates a minibuffer prompt for selecting the folgezettel parent. The minibuffer prompt is grouped by top-level index numbering (i.e. all notes whose numbering begins with “1=…” are grouped together), so users of vertico.el can use vertico-next-group
and vertico-previous-group
for quick navigation of the index.
[fn:5] So equivalent to “1=3a12c1” is “1=3=a=12=c=1” and “1=3a12c=1” and so on.
[fn:6] So “1=3a12c1” has sections “1”, “3”, “a”, “12”, “c”, and “1”.