Hello, attendees of EmacsConf 2022!
The title of my talk is:
"Build a Zettelkasten with the Hyperbole Rolodex."
My name is Ramin Honary.
I work as a software engineer
writing apps for a small machine learning consultancy.
I have been using Emacs since roughly 2018
after having switched from a workflow
using Vim together with Screen/Tmux for over a decade.
Today I'd like to talk a bit about
the Hyperbole package for Emacs.
Others are presenting talks later today
about Hyperbole as well,
including some of the the authors and maintainers,
so I won't go into too much detail
about how Hyperbole works.
Instead, I want to present
a more concrete use case for Hyperbole,
which is how to use it to facilitate
the Zettelkasten method.
Most Emacs users will probably be
more familiar with Org Roam.
Org Roam may even be the first thing that comes to mind
when you hear the word "Zettelkasten."
But personally, I use Hyperbole
because I found it easier to get started with
using it as an ideas database.
All you need to do is install the Hyperbole package
(which is available on GNU-ELPA)
and then set a few customization options.
There is nothing else you really need to do
to get started.
And also, Hyperbole works nicely with Org Mode.
So Hyperbole's built-in functionality
can be used as a nice, light-weight alternative
to other Emacs Zettelkasten packages.
This talk is for people who are curious about
getting started with the Zettelkasten method,
but are not ready to commit
to a more purpose-built solution like Org Roam.
So the thing I'd like people
to take away from this presentation
is that the Hyperbole Emacs package
provides you with a flat-file database called "HyRolo"
which you can use to store ideas.
Then you can use what Hyperbole calls "buttons"
(which are hyperlinks)
to execute arbitrary Emacs commands
and by inserting links into your database
that execute queries against the database itself.
These query-action links serve as
a means to link ideas together,
thus creating a functioning "Zettelkasten."
If this doesn't make sense to you,
I'll explain what all of this means presently.
So just a quick overview of what "Zettelkasten" is.
Note that most of what I say
about the Zettelkasten method
comes from a guy called Sascha Fast,
and his website: zettelkasten.de .
So a Zettelkasten is, in brief,
a database containing many nodes of interconnected ideas,
each idea being a single quantity of knowledge
(about a paragraph)
and linked to other related ideas.
Also, let me quickly mention
that there are actually many tools I use
that assist me with the zettelkasten method:
Hyperbole for hyperlinks;
Embark for general text editing;
Org Mode for markup;
Dired for managing large sets of files;
Consult, Vertico, Orderless, Marginalia;
for interactive search through directories and documents;
and Magit for revision control,
and syncing my database of ideas
across a few of my computers.
Each of these tools provides some unique functionality,
but today I will be focusing mostly on Hyperbole
and how it is especially useful
for the task of linking information together
which is the most important aspect
of the Zettelkasten methodology.
And now I'll briefly go over what Hyperbole is.
At it's core, Hyperbole is a simple markup language
specifically designed to markup hyperlinks.
Now, a hyperlink usually is only able to jump to
ordinary URLs and file paths.
Hyperbole extends the function of a hyperlink to provide
a simple human-readable markup
for executing Emacs commands (called "button actions")
and then, on top of this core functionality,
a few mini applications
for example "HyRolo" and "Koutline",
have been built to make Hyperbole more generally useful
as a personal information management tool.
"HyRolo" is the feature that I use as my Zettelkasten,
and in particular, the HyRolo search feature
in combination with
the usual Hyperbole hyperlink markup language.
So let me just quote the Hyperbole manual:
"Hyperbole includes HyRolo for convenient management of
hierarchical, record-oriented information.
Most often, this is used for contact management
but it can quickly be adapted to most any
record-oriented lookup task requiring fast retrieval."
So in other words, for example,
it can be used to run search queries
across the full set of nodes in a set of Org-Mode files.
This means we can use an Org-Mode file
as a flat-file database
in which entries in the database can be linked together.
This, in essence, is a what a Zettelkasten is.
HyRolo needs almost no configuration,
even if you are using it
for the purpose of Zettelkasten,
but you should at least make sure
you set the location of the database
in your Emacs config file, using the Customize system
or however you prefer to configure your Emacs.
I use "use-package", and on this slide I have here
an abridged version of what my "init.el" file
looks like for the Hyperbole package.
A few relevant environment variables are set:
the "hyrolo-file-list" variable
selects where to find Rolo database files
for the purpose of search. I have it set
to just the Zettelkasten flat file database.
And I also set "hyrolo-date-format" variable.
Each database entry has a time stamp, and
I use the time stamp as a unique ID
for each entry (that is, each idea node)
in the database.
Finally, before I get into the actual demo,
let me quickly explain
the Hyperbole mini-buffer menu system.
Mini-buffer menus in Hyperbole work just like
in an ordinary GUI,
except you typically enter into the mini-buffer menu
with a key binding instead of a mouse click.
To open the Hyperbole menu,
you use the Hyperbole universal leader key
that's C-h h, which by the way,
this rebinds the "view-hello-file" command,
which is a command that probably most people never use.
So all Hyperbole menu key sequences begin with C-h h.
Please remember this:
as I explain how to do things,
please don't worry too much
about the key sequences I use
to perform certain actions.
Really, I am just navigating
the Hyperbole mini-buffer menus.
It is a very discoverable and fluid user interface.
Anyway, now that we have configured our Rolo database,
let's see how we enter new ideas into the database.
And I will start with an empty database,
then I'll switch over to a more complete database
that I prepared for this demo. So...
first we type the Hyperbole universal leader key C-h h,
and then, you can see the menus down here
we type "r" for "Rolo" and "a" for "add".
That's C-h h r a to enter a new idea.
And this command is available globally so,
much like with the "org-capture" feature in Org-Mode,
you can run this command at any time,
at the very moment you want to enter an idea.
First we are prompted for an entry title,
and if you were using HyRolo as a contact list,
this is where you would enter the person's name.
I am using it as a Zettelkasten,
so I instead enter a title for my idea.
I'll just type in...
and as soon as I press enter after this prompt,
my Zettelkasten org file is opened,
a new entry with the timestamp is created,
and the cursor is placed at this entry
ready for me to enter the body text of the idea.
I'll type that in...
Now I save the "idea" file (C-x C-s)
and switch back to what I was working on before
with the usual C-x 0 (delete-window) command.
Next, I'd like to talk about
the HyRolo database search feature,
which is very useful.
The HyRolo search feature uses
only Emacs built-in functions
and there is no indexing
as with tools like "mlocate" or Org-Roam.
So far, I have not had any trouble with efficiency.
I don't know if at some point in the future,
it will start slowing down.
Emacs built-in search functionality
is already pretty efficient as it is.
It could also be that I am in the habit
of storing larger bodies of text in separate files,
and not in the flat file database.
Anyway, you can search
by regex, by string, or by words.
I personally find the string search
to be the most useful.
The difference between word search and string search
is that string search provides
logical query operators like AND, OR, XOR, and NOT.
Once you run a search query,
a "*HyRolo*" buffer is opened
with the query's results.
And this is a read-only-mode buffer
with a few useful single-key action bindings
for navigating the list of results
which I will now demonstrate.
By the way, I have now switched over
to a larger example Rolo database that I have created
to demonstrate more of the HyRolo features.
The HyRolo search is available
in the Hyperbole mini-buffer menu
so it is always available to you.
Start with the Hyperbole universal leader key C-h h
then "r" for Rolo and "s" for search. That is C-h h r s.
Now we are prompted for a search string:
I type in "Alice Abelton", and when I press enter,
the search results pop up
and the number of results is printed in the mini-buffer.
We could also enter a search expression
similar to a Lisp S-expression
with logical operators like AND or NOT,
but you would not need to quote the search terms.
So, for example (C-h h r s), I could write
"(and university character)" within parentheses
and this would find entries
that only contain both of the words
"university" and "character".
For the most part, I only really ever use
the ordinary string search without logical operators.
So as you can see, a search result buffer
called "*HyRolo*" has popped up
with all of the matching entries.
And the search results buffer is a read-only buffer
with several useful navigation key bindings:
I can press "o" to switch to "overview" mode,
which shows all of the headings, but no content.
This would include subheadings
with like 2 stars in front of it or 3 stars
I can press "a" to switch to "show all mode"
which shows all of the content under each heading.
If I know I am looking for a keyword
in a top-level heading,
I can press "t" to switch to the "top-level" view mode
which shows only the top-level headings.
As is always the case
with the Emacs default key bindings,
"n" and "p" move the cursor down and up lines,
so I can navigate the cursor downward
to an entry that looks interesting.
I can press "s" to show the content
of that particular entry.
I can press "h" to hide the entry again.
And I can press "e" or M-RET on the entry heading
to "edit" that heading (that entry),
which will open the Org-Mode file,
that is, the Zettelkasten database file
with the cursor at this particular entry.
Be warned that editing an entry creates a new timestamp,
which I do not need, and there is currently
no way to avoid this behavior.
I work around this by simply using the undo command
which removes the unwanted timestamp.
And so that is how I use the HyRolo search functionality.
Now... since the most important aspect of Zettelkasten
is linking ideas in the database,
how do we actually make this work in HyRolo?
So this is the secret sauce of Hyperbole,
and the key take-away
for this presentation (as I said earlier).
Hyperbole provides markup syntax
for executing arbitrary Emacs commands
so you can link HyRolo entries together
using the HyRolo search function.
Let me demonstrate this now.
I am back in my example HyRolo database,
and if you take a closer look
you can see some of the hyperlinks
that I already created
with the angle-round bracket syntax.
Now with the cursor inside of these brackets,
I can press M-RET to "click" on this link.
As you can see, the search query
corresponding to this hyperlink here has executed
and popped up the "*HyRolo*" search results buffer.
There is only one linked entry,
but the list of ideas that are produced
by the search query in this buffer here
are the list of all of the other ideas
that are related to this hyperlink
that we just clicked on here.
(Let me get rid of the other window...)
Now from within this "*HyRolo*" buffer,
I can navigate to another hyperlink...
and clicking on that updates the "*HyRolo*" buffer
with new results again.
I can just keep navigating through
all the Zettelkasten entries in this way.
And so this is it.
This is my simple but effective Zettelkasten,
constructed entirely with the functionality
already built-in to Hyperbole.
In the remaining time,
I'd like to talk about how Hyperbole hyperlinks work,
because it's slightly different
from how hyperlinks work in Org Mode
or with the Emacs clickable text properties.
The easiest way to create a hyperlink button
that runs an Emacs command
is simply to type the Emacs command as an S-expression,
but with angle brackets instead of parentheses.
If you were looking closely,
you probably already saw a hyperlink of this form,
an angle-bracketed Emacs command.
This hyperlink simply calls
the "hyrolo-fgrep" function with this string argument.
and so clicking on this button
is equivalent to running a HyRolo search
with the C-h h r s key sequence.
As you can see, clicking on it
produced the search results
for entries associated with that string query.
It's also possible to label an action
with a so-called "implicit link",
and that's this angle-and-square bracketed notation.
If I click on this button,
it will activate this action
to the right of the colon separator,
and there are the relevant search results
from that string query.
Finally, there are "explicit links",
which I find to be especially useful
for the Zettelkasten method.
I've already shown an example
of using an explicit link before.
What makes explicit links so useful is, firstly,
that the button works with just the label alone.
There is no need to write an S-expression or anything.
You can write the link label
inline with the body text of the idea.
(For example, like this.)
Explicit links are identified by their label,
so they are especially good for
the names of people and places.
By the way, this Zettelkasten database is for
a fictional story I started writing
for the purpose of demonstrating HyRolo
in this presentation, and I had so much fun writing it
that I may actually continue developing this story.
Anyway, let's create a new explicit link
and a new idea entry for a character in the story.
So suppose I want to create a new idea node entry
for this fictional character here,
and I'll also want to link this entry to that node.
Since hyperlinks are just string search,
we don't actually need to have
an entry in the database for this character.
The worst that can happen is that the hyperlink
executes a search that returns no results.
So it's OK to create the hyperlink
before we have an actual entry for this person.
(I'll just M-w copy the name.)
Now I use the universal Hyperbole leader key C-h h,
and then "e" for "explicit links"
and "c" for "create". That's C-h h e c.
We are prompted for an entry label
but it defaults to the text highlighted by the region,
so I just press enter.
Now it prompts for a button type,
so I select "hyrolo-fgrep"
(and there's Orderless helping me go faster),
and since "hyrolo-fgrep" requires
a string argument for the search query,
I am prompted for the query string.
I'll type in "character:", (yank "Kerri Katz's" name)
and there we are, the link has been created, and
(let me just get rid of the # character)
I can try it out.
There's no search results. That's fine.
We haven't created an idea entry yet
for this character now.
So let's go ahead and do that now.
If we remember how to create a new idea,
it's C-h h r a, and then I type "character:"
and then yank the name again.
Now a new node has been created,
and I can start describing this character.
Notice that I like to precede my characters
with the keyword "character:" colon.
This technique helps me to create hyperlinks
using more descriptive search queries
that return fewer but more useful search results.
And finally, I can create an explicit link
from this character back to
the other character (her boyfriend).
I just type in "<(Bertrand Becket)>",
and this explicit link has already been created
so I don't need to create it again. It just works.
Hyperbole identifies buttons by their label,
so as long as an explicit link button with that label
has been created before,
I just can type in the button with markup by hand,
and then I can just use it.
Now I am back to the search results
for the boyfriend character.
I hope you can see how minimal but useful
is this particular Zettelkasten technique I have
that uses this "HyRolo".
I should also make clear that Hyperbole explicit links
are encoded in a separate file in the same directory
as the Zettelkasten flat-file database.
(So, let's go back to that and C-x C-f ".hypb").
You should not edit this file by hand,
but it is human readable,
so it works well with Git
and other revision control systems.
Whenever an explicit link is activated,
it consults this file and runs the associated action,
which, in the Zettelkasten use case,
will always be to run a HyRolo search query.
The advantage of keeping a separate table of links
is that you can edit the link action
(that is, the search query) in just one place,
and the updated button action works everywhere
without having to change any other files.
So, that is all for today.
Thank you so much for listening to my talk.
I'll be available for questions
for the next 20 minutes or so.
If there are any questions that I cannot answer,
you will have a chance to ask
the author of Hyperbole himself, Bob Weiner,
later today after his presentation.
Thanks for your attention!