Over at Ray on Emacs, Raymond Zeitler writes about the Emacs Diary for the June Emacs Carnival. The June topic is underappreciated Emacs built-ins and for Zeitler that’s Emacs Diary. He was a little disconcerted at first by being offered a blank screen for each entry. He wondered where his previous material went but he came to appreciate the fresh start that that blank buffer gave him. He goes on to describes some of the functions and capabilities of Diary.
I recently started keeping a personal journal too and considered using Diary—it was, of course, going to be written in Emacs in any event—but decided to simply use Org mode instead. I have an Org capture template to start a new entry—just like Zeitler’s method—but I can, of course, just bring up the journal Org file directly to see or edit anything.
I’ve found that this works well for me. I don’t write in my journal everyday, just when something worth recording happens, so I don’t care about things like when the sun rose or set, what the temperature was on that day; just what happened that I felt was worth remembering. Of course, if I did care about such things it would be easy to arrange to add them.
Or I could just use Diary. That’s the beauty of Emacs: you can make it do pretty much whatever you need it to and very often what you need is already there.
The folks who 'grok' Emacs aren't wizards. They don't learn Emacs, per se, but instead they learn the handful of built-in commands for asking Emacs about Emacs. Those same commands work on themselves, so once you know them you can teach yourself everything else you need to know about Emacs. This post tours that machinery (the C-h help family, apropos, Info, xref, describe- and friends) by following the questions a curious beginner typically asks, and ends by fishing a built-in game out of Emacs and reading its source with that machinery. Emacs teaches itself in this way. In other words, Emacs doesn't give you a fish, it teaches you how to fish!
2. About emacscarnivalbuiltins
Give a person VSCode, and you feed them for a day.
Give a person Emacs, and you feed them for a lifetime.
My memory is always hazy with quotes like this, but if my memory hasn't failed me this time, this is a century-old proverb about the fortitude of learning craft over the weakness of receiving crafts. Some nagging feeling tells me the proverb was about fish, but I digress….
This post is my entry for June's Emacs Carnival (hence the punny title), whose theme is Underappreciated Emacs built-ins. I did one for May too, where I rambled about the deeper patterns that make Emacs powerful. This month I want to be more concrete and practical, because the built-in feature I most want to celebrate is the one that teaches all others. Yes, I'm about to flog the dead unicorn of Emacs's autodidactic nature.
Whenever you hear an Emacs elevator pitch, or a response to an overwhelmed beginner's question of "where do I even start?", you'll hear some configuration of the following phrases:
"Everything in Emacs is introspectable"
"Emacs discoverable"
"Emacs is an autodidact" (a lovely phrasing I'm borrowing from Prot)
"Emacs is self-documenting"
Although true, they're all slogan-ish and platitude-inal, and slogans tend to slide off an Emacs newbie like water slides off a fish.
So this post (and the companion video below) is my attempt to show the built-in machinery that lets Emacs teach itself to new and veteran users alike. Keeping honest with the theme of June's Emacs Carnival, this all runs from bare emacs -Q, and so that's how I'll demonstrate it.
Something I hope you appreciate after reading (or watching) is that these auto-discovery features can make learning Emacs an engaging adventure game. Emacs is the map, you are the intrepid Zoombini-esque adventurer, and Emacs's auto-discovery feature set is your 'navi'.
As this is part of a blog carnival, unlike my typical more clinical posts the prose here-in will be whimsical and silly, and filled with a gratuitous number of fish and maritime puns. If you don't like that vibe, you can skip reading, and go fish yourself 😜. I'm only be partially cheeky there. If you want to bounce, just type C-h C-h and read the buffer that shows up.
But if I've hooked you, ready your tackle box and settle in for some serious schooling.
3. The Strange Loop (the Fish that Teaches Fishing) thesisrecursion
If you were hoping for something like M-x go-fish, guess again.
This trick is fascinating to me, and I think it's the most illustrative vignette of Emacs's autodidactic nature. Open emacs -Q, and type:
C-h k C-h k
The first C-h k runs describe-key, which says "press a key and I'll tell you what it does." The second C-h kis the key you press that you want a description for. So describe-key describes describe-key. I do apologize for the recursive prose, but it's the kernel of this whole idea.
When you do this, Emacs displays a *Help* buffer explaining describe-key:
C-h k runs the command describe-key (found in global-map), which is an
interactive native-comp-function in ‘help.el’.
It is bound to C-h k, <f1> k and <help> k.
It can also be invoked from the menu: Help → Describe → Describe Key
or Mouse Operation....
(describe-key KEY-LIST &optional BUFFER)
Inferred type: (function (&optional t t t) t)
Display documentation of the function invoked by KEY-LIST.
KEY-LIST can be any kind of a key sequence; it can include keyboard events,
mouse events, and/or menu events. When calling from a program,
pass KEY-LIST as a list of elements (SEQ . RAW-SEQ) where SEQ is
a key-sequence and RAW-SEQ is its untranslated form.
While reading KEY-LIST interactively, this command temporarily enables
menu items or tool-bar buttons that are disabled to allow getting help
on them.
Interactively, this command can’t describe prefix commands, but
will always wait for the user to type the complete key sequence.
For instance, entering "C-x" will wait until the command has
been completed, but ‘M-: (describe-key (kbd "C-x")) RET’ will
tell you what this prefix command is bound to.
BUFFER is the buffer in which to lookup those keys; it defaults to the
current buffer.
Probably introduced at or before Emacs version 22.1.
As you can see, that *Help* buffer has a line like "describe-key is an interactive compiled Lisp function in help.el", and help.el is a link to the file implementing describe-key. Click it (or hit RET on it) and Emacs takes you directly to the source code of the function you just 'described'.
The surface value of this trick for beginners is that you can immediately get the docs and source code links for any command you type in, solving the mysteries created by folks telling you to "C-x [x] to do [blank]". The deeper value of this trick is that Emacs is loopy in its autodidactic way, because you can literally read how the thing that explains things explains things.
For more depth, realize through this answering of the question "what does C-h k do" that every door in Emacs opens into a room that contains not only a description of that door, but links to and descriptions of the other doors leading out of and into that room (see my commentary on graphs).
Even with this single trick, you realize that you don't really "learn Emacs". Instead, you learn the small set of commands for asking Emacs about Emacs. These aren't solid analogies, but Hofstadter might call it a strange loop, and alchemists might draw this as an Ouroboros (a self-cannabilizing snake). I'm clowning at a carnival right now, so I'll call Emacs a fish that teaches fishing 🎣.
The rest of this post is organized around the questions a curious Emacs autodidact can ask, in roughly the order they would ask them. Watch for the loops and edges, as every tool below can be pointed back at itself (loops), and every answer to a question elucidates the relationships (edges) between that answer and the related Emacs goodies.
4. "Where Do I Even Start?" helptutorial
The single most important key in Emacs is C-h (Help). If you remember nothing else, remember that C-h is the universal "explain this" prefix, and that you can ask the help system for help about the help system.
Key
Command
The question it answers
C-h C-h
help-for-help
"What are all the C-h options?" (help on help)
C-h t
help-with-tutorial
"Walk me through the basics, hands-on."
C-h r
info-emacs-manual
"Open the full Emacs manual."
The first thing you should do is press C-h C-h. This will show all variants of "help with this [thing]". Sorry for more graph-speak, but in my opinion this is the entry node to the vast Emacs network. The C-h k for "help with this key" is only one of the many 'things' you can get help with. See what this looks like in the image to the right.
The second thing you should do as a newcomer wading into Emacs is to press C-h t, which takes you through the tutorial, an interactive buffer that teaches the basics of movement and editing. This is the most literal "autodidact" feature.
A useful shortcut to the Emacs manual is C-h r, a mnemonic keybinding for 'reeling' in the full Emacs manual 😉.
5. "What Did I Just Do?" introspectionhistory
A huge amount of Emacs learning happens retroactively. You follow a tutorial, reddit comment, or README and press some keybindings to make magic happen (that's the fish), and then you want to learn what that invocation was and how it worked (that's the fishing).
Key
Command
The question it answers
C-h l
view-lossage
"What were my last ~300 keystrokes?"
C-x ESC ESC
repeat-complex-command
"Show me the Lisp of the last command I ran."
C-h e
view-echo-area-messages
"What has Emacs been telling me?" (the *Messages* log)
view-lossage is like a flight recorder. It replays your recent keys so you can reconstruct "what did I press to make that happen?", or more likely in the early days of frustration "what in the ever-loving FISH was that?".
My favorite command here is repeat-complex-command (C-x ESC ESC). Any command that read input from the minibuffer gets stored as an honest-to-goodness Lisp form, and you can see any one of these by using repeat-complex-command. For example, if you run a query-replace, then hit C-x ESC ESC, Emacs literally shows you the executed (query-replace "foo" "bar" nil ...) lisp code that you composed when you ran that query-replace command. So, not only can Emacs tell you what command you ran (view-lossage), it can also tell you exactly what Lisp was produced as a result of your interaction post-command-invocation (repeat-complex-command).
*Messages* (C-h e) is probably my most used trick. Everything that flashes in the echo area is recoverable with this command. This is especially useful when 1 interaction results in many echo area messages that flash too quickly for you to read them all.
Other editors can't 'show you the receipts' in this way, but Emacs keeps itself nice and auditable with these 3 commands.
6. "What's Under my Cursor?" introspectioneldoc
Point (Emacs-speak for the 'cursor') is always sitting on something, and Emacs can describe that something in exhaustive detail (the character, its font, its text properties, etc…).
Key
Command
The question it answers
(passive)
eldoc-mode
"What's the signature/doc of the thing I'm typing?" (live)
C-h .
display-local-help
"Is there context help for the thing right here?"
C-u C-x =
what-cursor-position
"What exactly is this character — codepoint, face, the lot?"
M-x describe-char
describe-char
The full-buffer version of the above.
C-h m
describe-mode
"What modes are active here, and what can they do?"
Eldoc is a passive but useful member. It's on by default in programming buffers since Emacs 25, and it prints the function signature or variable doc for the thing under point into the echo area.
C-u C-x = and describe-char are like an electron microscope, but for characters instead of electrons. For any character, it tells you its Unicode codepoint and name, the face(s) painting it, and every text property associated with it. (Recall from last month that everything in Emacs is characters-plus-properties in a buffer, and describe-char is how you read that substrate directly.)
C-h m (describe-mode) is a major/minor-mode spirit guide. When you press it in a buffer, it assembles the documentation and the full keybinding list for the current major mode and every active minor mode. When I'm exploring a new major mode, I hit C-h m, and the resulting Help buffer guides me through what this set of modes provides, and how I can leverage them.
7. "What Can I Do Right Now?" discoverabilitykeys
This is likely the family of commands that people have in mind when they say Emacs is "discoverable." What makes this so usable is that you do not have to know a command's name or key in advance, because Emacs will enumerate the possibilities for you (completing read to the rescue!).
Key
Command
The question it answers
C-h b
describe-bindings
"What is every key bound to right now?"
C-h k
describe-key
"What does this key do?" (key → command)
C-h w
where-is
"Where is this command bound?" (command → key)
(prefix) C-h
which-key-mode
"I pressed a prefix — what can follow it?" (live popup)
M-x
execute-extended-command
"Let me search all commands by fuzzy name."
M-`
tmm-menubar
"Give me the menu bar in the minibuffer."
Notice C-h k and C-h w are inverses. C-h k goes key→command, and C-h w goes command→key. That bidirectionality is just chef's kiss 😗🤌. It means that you can interrogate the binding between keys and commands from either side of the relationship.
Two of these deserve a special carnival spotlight because of how elucidating they are for a built-in:
First, which-key. After enabling it with which-key-mode, when you press any prefix like C-x and pause, a popup lists every key that can follow and what it does. As of Emacs 30 this is in core (enable it with M-x which-key-mode).
Second, M-x, mostly known as a command runner, is itself a discovery engine for commands. Thanks to completion (see my series on this topic) you type a small fragment of what you want and Emacs filters the entire command namespace live (and helpfully shows the keybinding next to commands that have one). This is so powerful because it obviates difficult recall, and instead lets you easily recognize the command you're after. In this way, you don't need the right bait for your target, just a vague wiggle. This is exactly the ICR pattern I went on about last month, here playing a second role as a teaching tool. To emphasize the loop again, with M-x at your disposal, you don't have to remember any of these help commands, just intuitively use the words "help", "describe", "which", "where", and "what".
8. "What is this Thing?" helpapropos
Once you have a name (of a command, a function, a variable, a face, etc…) Emacs can tell you all about it.
These describe- commands are worth adding to your personal list of favourites. Each one produces a navigable buffer of documentation, as well as links to other describable things (there's that loop again).
Key
Command
The question it answers
C-h f
describe-function
"What does this function/command do?"
C-h v
describe-variable
"What is this variable, its value, its doc?"
C-h o
describe-symbol
"Tell me about this symbol — function or variable."
C-h x
describe-command
"Describe this (interactive) command specifically."
Although I don't use this much nowadays, you can cast a wider net when you don't know the name of the thing you're looking for, but possibly only a description of it. That's where the apropos family welcomes you with open arms, providing an Emacs-wide search across a variety of contexts.
Key
Command
The question it answers
N/A
apropos
"What symbols match this word?"
C-h a
apropos-command
"What commands match this word?"
C-h d
apropos-documentation
"Search the docstrings, not just the names."
apropos-variable
"What variables match this word?"
apropos-value
"What variables currently hold this value?"
apropos-documentation (C-h d) stands out with special value because it trawls the full text of every docstring in your session. So, you can find a command/variable/function by describing it when you have no idea what it's called. A good example: "I want to make this text lowercase" → you'd naturally search lowercase, but the command is downcase-region / downcase-word. The name says "downcase," so a name search for "lowercase" leaves you floundering. But C-h d lower case RET finds them, because their docstrings say "Convert the region to lower case."
A tragically underrated discovery vector is M-x shortdoc-display-group (Emacs 28+). It shows grouped, example-driven documentation by topic, each with a worked example.
9. "Where Can I Read More?" infodocumentation
describe- answers ad-hoc questions, but sometimes you want to read the actual docs. To me, this is the difference between search and browse. When I'm starting out, I like to unblock myself with the search features that the above commands provide, and after I'm comfortable, my curiosity leads me to browse the source, or 'RTFM', which stands for "Read the Fishing Manual".
Luckily for me, Emacs ships entire manuals as hyperlinked, searchable Info documents, and it can jump you from a symbol straight to its place in the manual.
Key
Command
The question it answers
C-h i
info
"Open the Info reader — every installed manual."
C-h r
info-emacs-manual
"Open the Emacs user manual specifically."
C-h S
info-lookup-symbol
"Jump to this symbol's entry in the relevant manual."
C-h p
finder-by-keyword
"What packages exist for a given topic?"
C-h n
view-emacs-news
"What changed in recent Emacs versions?" (the NEWS file)
Inside Info, the whole document is a graph you walk (more about my obsession with graphs below). RET follows a cross-reference, l goes back, m picks a menu item, i jumps to an index entry, s searches. Try all these out, and see what other moves are available with the M-x info- trick we described above.
This kind of navigation is the same "follow the reference" experience as reading code with xref (next section), but for docs. Emacs loves its patterns in this way, and it makes this 'graph' traversal reflexive in a variety of code and non-code contexts.
These are deeper waters for beginners, but you can also read the Elisp manual in Info to learn how to write your own extensions or beef-up your configuration in Emacs. That's how I learned the language.
C-h p (finder-by-keyword) is undersung in my opinion. It provides a built-in package browser organized by keyword. For example, you can pick games and Emacs lists every game library shipped in-box (which is exactly how we're going to go fishing in a moment 🐟).
10. "How Does it Actually Work?" sourcexref
This feature really sets Emacs apart from other editors. Because nearly all of Emacs is written in Emacs Lisp, "read the documentation" can always become "read the implementation" in a single keystroke.
Key
Command
The question it answers
M-.
xref-find-definitions
"Jump to the definition of the symbol at point."
M-,
xref-go-back
"Jump back to where I was." (the return half of the pair)
find-function
"Take me to the source of this function."
find-variable
"Take me to where this variable is defined."
find-library
"Open the source file of this whole library."
You don't even need to invoke these directly, because every *Help* buffer from C-h f already contains a "defined in foo.el" link, so the path from "what does this do" to "here is exactly how it does it" is just 1 smash of your RET key.
M-. / M-, (xref) are the generalized "follow upstream / come back" pair. By the way, they not only work on Elisp out of the box, but also on your own code once a language server or tags table is in play. The reflex is identical whether you're hardly working (on Elisp hacking) or working hard (at your day job).
These functions in particular lend credence to the "everything is introspectable in Emacs" claim. From scales to skeleton 😉.
11. "Let Me Just Try It" evalrepl
We've talked mostly about reading up until this point, but what about doing? After all, Emacs is a live Lisp system, so you can evaluate expressions against the very session you're in and change it while it's running. This is what people mean when they say something like "Emacs is powerful because it can be mutated at runtime".
Key
Command
The question it answers
C-x C-e
eval-last-sexp
"Evaluate the expression right before point."
M-:
eval-expression
"Evaluate one expression I type in the minibuffer."
M-x ielm
ielm
"Give me a Lisp REPL."
(buffer)
*scratch*
"A buffer where C-j evaluates as I go."
Try it out…. Open the *scratch* buffer (or any buffer for that matter), and type (+ 1 2), move your cursor to the end of the closing paren, hit C-x C-e, and 3 appears in the echo area. Better yet, if you type C-u C-x C-e, then you see that 3 inserted next to the expression (did somebody say iLisp notebook)?
Similarly, you can type the name of any variable you just learned about and evaluate it to see its live value. Or you can call any function you just read the source of and see what it returns. This works on Elisp code in any buffer, so for example, if you come across a form you want to evaluate while reading the Info manuals, you can simply evaluate in-place.
This closes the loop between the documentation and the things they document. By the way, if you ever want to go really deep into seeing how functions get evaluated, M-x trace-function, M-x debug-on-entry, and edebug let you watch Emacs execute itself step by step.
12. "Where Are the Levers?" customizeconfig
People bang on about Emacs being so customizable, but how do you become aware of what you can customize? How do you trim the tackle to your liking?
Every package exposes a set of levers (variables you're meant to tune) and Emacs has a built-in, self-documenting UI for finding and flipping them without writing Lisp.
Command
The question it answers
customize-mode
"What can I tune about the mode I'm in right now?"
customize-group
"Show me all the levers for this package."
customize-apropos
"Search all settings matching a word."
customize-browse
"Let me browse the whole settings tree."
The Customize interface is itself a teaching document because each setting shows its docstring, its type, its default, and its current value, with toggles and dropdowns appropriate to the type.
Often, when I'm learning a new package, I first look at the README or the author's config to get an idea of how it can be configured, but I wonder if M-x customize-group RET <package> RET would be better, as it shows me the full set of knobs that the package author decided to expose, not just the ones they decided to configure for themselves.
Something else often overlooked, but worth noting, is that anything you set via the Customize UI gets written to your init.el file by default, so that these settings persist across Emacs sessions. In my May carnival post, I reluctantly admitted that I learned programming with VBA in Excel, and I did so with the macro recorder. I learned how to customize Emacs in the same way, except Customize was effectively my 'macro recorder' for seeing how to configure via Elisp rather than the UI.
13. The demo: fishing for games 🎣 demogames
Let me end the way the video ends, by demonstrating autodiscovery on something delightful, games 😍.
13.1. Casting the line: discovering that Emacs has games at all
You don't have to be told Emacs has games (even though I just did lol), because you can discover it, by any of several built-in roads we just walked:
Through the manual.C-h r to open the Emacs manual, then search its menu for the node titled "Amusements." It lists them: tetris, snake, pong, gomoku, 5x5, bubbles, life, hanoi, the dunnet text adventure, and doctor (a hilariously useless built-in ELIZA you can have a feelings-chat with).
Through the package finder.C-h p (finder-by-keyword), pick games, and read the list of game libraries directly.
Through completion.M-x tetr and watch tetris surface; or C-h a game RET (apropos-command) to find commands matching "game."
Although this seems redundant, the redundancy is supporting discoverability here. There is no single magic incantation you need to learn to discover games, there are many paths that can lead you there.
Pick tetris (the best one IMO), M-x tetris RET, and play a round.
13.2. Reeling it in: a facilitated code review of tetris.el
Now the payoff. As magical as tetris in Emacs seems, it is of course not a black box. It's a few hundred lines of Emacs Lisp, and we can read it using the exact tools the rest of this post is about. Watch how every section above comes back (we've nearly caught our first fish!):
Open the source.M-x find-library RET tetris RET ("How does it actually work?") displays tetris.el in a buffer.
Inspect a thing at point. Eldoc is already narrating signatures in the echo area as we move. Land on a call to defvar or to a function like gamegrid-init and hit C-h f ("What is this thing?") to read its docstring.
Follow the reference. On gamegrid-init, hit M-. (xref-find-definitions, "How does it work?") to jump straight into gamegrid.el, the generic game-board engine that tetris, snake, and pong all share. Then hit M-, to come back. We just learned that Emacs factored a reusable arcade substrate out of its toys!
Consult the manual for usage. On a built-in we're unsure how to use, C-h S (info-lookup-symbol, "where can I read more?") jumps to its entry in the Elisp reference.
Try it live. Curious what tetris-default-tick-period holds, or what a board cell looks like? C-h v to read it, or evaluate it in *scratch* ("let me just try it") to see the live value.
Find the levers.M-x customize-group RET tetris RET ("where are the levers?") shows the tunable settings the author exposed, like board size, colors, and speed.
Throughout this adventure, at no point did we leave Emacs or consult anything that didn't reside within it. We learned how a built-in game works and rehearsed every introspection reflex on real code in the process.
If you followed along with this, then congratulations are in order, because you, my fellow EmacSapien, have just caught your first fish.
14. A Brief Bubble on Graphs
I think about everything, not just in Emacs but also in the world, as a graph. Every thing is a node, and every thing has relationships, or edges, with other things.
In Emacs, consider how a function might be a node. Consider what its edges might be:
This function has direct relationships. For example, it has a documentation page, and file that implements it, and references in the info manual. This function also has indirect relationships. For example, this function calls other functions and it is called by other functions. Indirection is part of computer code, whether you like it or not.
As we've seen, Emacs provides numerous facilities for traversing both the direct and indirect relationships for any node it presents. What's more, opening a Help buffer on any symbol shows you the locality boundary of the thing you are getting help with, filtering the enormous neighborhood of related things to only the most meaningful neighbors.
Because I imagine everything as a graph, I'm a firm believer that tools which facilitate graph traversal are worth learning. They help us to tame the overwhelming networked complexity of the organic world in which we reside. Emacs's graph traversal tools, in this way, are the best in class, and that's why I felt so compelled to write this article.
15. Reprise: what the slogans actually mean thesis
Now that we've seen the autodiscovery in the concrete, let's lend credence to the abstract slogans:
"Self-documenting" — every function and variable carries a docstring that is queryable at runtime (C-h f, C-h v, C-h d, shortdoc). The documentation lives inside of Emacs. It is an attribute of the live object.
"Everything is introspectable" — the running Emacs will tell you about its keys (C-h b, C-h k, C-h w), its modes (C-h m), its characters (describe-char), its symbols (C-h o, apropos), and its own source (M-., find-function).
"Discoverable" — you navigate by recognition, not recall. Completion in M-x, the which-key popup, describe-bindings, the package finder, and Info's indices all enumerate your options in context.
"An autodidact" — the built-in tutorial (C-h t), the 'what just happened' receipts (C-h l, C-x ESC ESC), and the live REPL (*scratch*) mean the editor's primary curriculum is itself.
When people say Emacs is hard, I think they've mistaken unfamiliar for opaque. The whole point is that Emacs is the least opaque tool I've ever used, because it explains itself so well.
As a quick note: you've likely heard folks say that Emacs skills 'amortize' over time, and that's why they're worth the time investment. Learning Emacs's autodiscovery features is the single most amortizing skill you can learn, whether you're new or old to the system, and you'll realize a higher ROI on this than anything else you pick up in Emacs.
Give a person a fish 🐟. Or hand them Emacs, and let them ask the fish how to go fishing.
16. A closing remark
Open this article in the built-in eww to re-read this whole post inside Emacs and run C-h f / M-. on every symbol I mentioned. You'll learn more from Emacs about Emacs than you did from me. 😉
When I adopted Emacs in July of 2000, I hunkered down to learn the
keybindings. But after I learned the basics1 I started
to RTFM (C-h r), and I was instantly drawn to the
Calendar/Diary2 node, which I consider to be an
underappreciated Emacs built-in, and, therefore, the topic of Emacs
Carnival for June 2026.
Back then I mistook "diary" to mean a blank-page-confidant into
which we write our thoughts, fears, ambitions or even just what we
had for dinner last night. At that time I'd been writing in
a journal for about 24 years (yes, since 1976, on and off), so my head
swelled with ideas of using Emacs for a revamped computerized
version. I imagined being able to forward-search-regexp
in order
to find, for example, that weird dream I wrote about in which I
caught a toad that was hopping around the kitchen and then turned
into a hot coal sizzling in my hand...
I used diary-block functions to date my entries and
organize the content. I ended up making four such entries from 2003
to 2004. But each day following the entry, M-x diary
would display a nearly blank buffer, showing only the day's date at
the top followed by a line of equal signs and perhaps a holiday.
Where did yesterday's entry go?! It was disconcerting that those
words "vanished" into thin air magnetic film or
silicon.
Today, however, I appreciate the simplicity of that approach -- a
clean slate sans distractions. But back then I was accustomed to
seeing a vast amount of my writing, which fed my ego.
But that's not all there is to appreciate. There are several
functions that can be used for "an entry" in addition to
diary-block, such as diary-anniversary, diary-cyclic, diary-float or even just a simple line that begins with a date and a brief note. This is not an all-inclusive list.
Every fancy diary buffer can show local time of sunrise and sunset;
to do this, include diary-sunrise-sunset in the diary file.
Include diary-lunar-phases to show one of the four
phases of the moon when one is active on that day; the
local time of that moon phase will be included.
What follows is an abbreviated and edited listing of my diary
files. Note how I've structured diary into a hierarchy
using include statements.
2026-06-17 02:25 GMT Important updates: First, you'll need to modify two hook variables in order
for the include statements to work. Please see
the help
for Fancy Diary Display. I also "use the normal hook
diary-list-entries-hook to sort each day's diary
entries by their time of day," which is described at the top of that
page. Second, specify the full path to the included files.
I've modified the two include statements to add the "~/" path. This
is needed only if you want to press TAB on the item in the Agenda in
order to focus the diary entry.
The beauty of this is that these events will show up in Org Agenda
at the appropriate times when org-agenda-include-diary
is non-nil.
Four examples are shown below. Here are some things to note:
The content that's derived from the diary file has "Diary" for value of CATEGORY.
The Sunrise / Sunset lines are supposed to show the time of
each occurance. However, the time for Sunrise isn't displayed;
rather, it's indicated by its position on the time grid. The times for both the New Moon and the Solar Eclipse are indicated by the time grid, as well, and are expected to peak at 13:38 in my area. That's something to look faroward to!
Sometimes I include links in my headings. In this case I can
follow a link to the credit card website to pay the Visa
card.
Even a link in the dairy file will be rendered
in the Agenda properly, as shown in the reference for Richard
Stallman's birthday.
file listing: diary
# -*- mode: diary -*-
#include "~/diary-anniversaries-property"
#include "~/diary-birthdays-friends"
%%(diary-sunrise-sunset)
%%(diary-lunar-phases)
%%(diary-remind '(diary-anniversary 3 16 1953) 14) [[https://html.duckduckgo.com/html/?q=Richard+Stallman+birthday][Richard Stallman's birthday]] in 14 days
%%(diary-block 6 21 2004 6 21 2004) The summer solstice. I
always take time to observe the position of the sun on this
day, especially in the morning and evening. Sunrise was at
5:16am and sunset will be at 8:29pm. From today onward, the
days will be getting shorter. At first it will be
imperceptible, but in September, it'll be quite noticeable.
file listing: diary-anniversaries-property
# -*- mode: diary -*-
# Recurring Property events or records
%%(diary-remind '(diary-date 7 3 '(2023 2026 2029)) 30) Car Registration is due
%%(diary-anniversary 8 12 2022) Kitchen Cabinets Painted %d Years Ago
file listing: diary-birthdays-friends
# -*- mode: diary -*-
# Birthdays of friends
%%(diary-anniversary 8 13) Bucky Thorndike Miller's Birthday (Does Dave still have his guitar amp?)
%%(diary-anniversary 2 13 1966) Ben's %d%s Birthday
Day-agenda (W11):Tuesday 16 March 2027 Diary: 7:03 ┄┄┄┄┄ Sunrise (EDT), sunset 18:58 (EDT) at Home (11:54 hrs daylight) 8:00 ┄┄┄┄┄ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ BILLS: 9:00 ┄┄┄┄┄ Deadline: TODO Visa Card LINK:Bills::Credit: 10:00 ┄┄┄┄┄ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ 12:00 ┄┄┄┄┄ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ 14:00 ┄┄┄┄┄ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ 16:00 ┄┄┄┄┄ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ 18:00 ┄┄┄┄┄ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ 20:00 ┄┄┄┄┄ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ Diary: Richard Stallman's birthday in 14 days
Day-agenda (W23):Wednesday 3 June 2026 Diary: 5:19 ┄┄┄┄┄ Sunrise (EDT), sunset 20:20 (EDT) at Home (15:00 hrs daylight) 8:00 ┄┄┄┄┄ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ 10:00 ┄┄┄┄┄ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ 12:00 ┄┄┄┄┄ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ 14:00 ┄┄┄┄┄ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ 16:00 ┄┄┄┄┄ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ 18:00 ┄┄┄┄┄ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ 20:00 ┄┄┄┄┄ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ Diary: Reminder: Only 30 days until Car Registration is due
Day-agenda (W33):Wednesday 12 August 2026 Diary: 5:58 ┄┄┄┄┄ Sunrise (EDT), sunset 19:54 (EDT) at Home (13:56 hrs daylight) 8:00 ┄┄┄┄┄ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ 9:00 ┄┄┄┄┄ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ 10:00 ┄┄┄┄┄ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ 12:00 ┄┄┄┄┄ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ Diary: 13:38 ┄┄┄┄┄ New Moon (EDT) ** Solar Eclipse ** 14:00 ┄┄┄┄┄ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ 16:00 ┄┄┄┄┄ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ 18:00 ┄┄┄┄┄ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ 20:00 ┄┄┄┄┄ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ Diary: Kitchen Cabinets Painted 4 Years Ago
Day-agenda (W32):Saturday 13 August 2022 Diary: 5:59 ┄┄┄┄┄ Sunrise (EDT), sunset 19:53 (EDT) at Home (13:53 hrs daylight) 8:00 ┄┄┄┄┄ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ 10:00 ┄┄┄┄┄ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ 12:00 ┄┄┄┄┄ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ 14:00 ┄┄┄┄┄ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ 16:00 ┄┄┄┄┄ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ 18:00 ┄┄┄┄┄ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ 20:00 ┄┄┄┄┄ ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ Diary: Bucky Thorndike Miller's Birthday (Does Dave still have his guitar amp?)
1My requirements (the basics) for a text editor were:
The doric-themes are the minimalist counterpart of my modus-themes
and ef-themes. They define few colours and exercise restraint in how
they customise faces. This means that there rarely is a context that
has red, green, yellow, blue, magenta, and cyan. Those are reserved
for cases where colour-coding is needed. Whereas with my other themes
colour is used with the dual intent of establish rhythm and order in
addition to any colour-coding.
Because of this, it is difficult for me to test the relevant values.
Each Doric theme defines entries in its palette like fg-red and
bg-blue. So I decided to write a small snippet that shows text which
uses those colours in context.
The idea is to create faces that get the appropriate :foreground and
:background attributes with their proper values. Then write text in
a buffer that displays each face.
(defconsttest-doric-accents'(fg-redfg-greenfg-yellowfg-bluefg-magentafg-cyanbg-redbg-greenbg-yellowbg-bluebg-magentabg-cyan))(dolist(accenttest-doric-accents)(custom-declare-face(intern(format"test-doric-%s"accent))nil"Test.":group'doric-themes))(defuntest-doric-set-accent-faces()(doric-themes-with-colors(let*((predicate(lambda(symbol)(string-prefix-p"bg"(symbol-namesymbol))))(foregrounds(seq-removepredicatetest-doric-accents))(backgrounds(seq-filterpredicatetest-doric-accents))(foreground-faces(mapcar(lambda(accent)`(,(intern(format"test-doric-%s"accent))((t:foreground,(symbol-valueaccent)))))foregrounds))(background-faces(mapcar(lambda(accent)`(,(intern(format"test-doric-%s"accent))((t:background,(symbol-valueaccent):foreground,fg-main))))backgrounds)))(apply#'custom-set-faces(appendforeground-facesbackground-faces)))))(add-hook'doric-themes-after-load-theme-hook#'test-doric-set-accent-faces)(defuntest-doric-show-accents()(interactive)(let((buffer(get-buffer-create"*test-doric-themes-accents*")))(with-current-bufferbuffer(erase-buffer)(dolist(accenttest-doric-accents);; Pangram from my `show-font' package...(let*((text"Protesilaos may find zesty owls and quiet jays vexing the black cat")(styled(propertizetext'face(intern(format"test-doric-%s"accent)))))(insert(format"%s\n"styled)))))(display-bufferbuffer)))
Reload the theme for changes to take effect.
And, yes, I had the motivation to write this because I am developing
new themes.
In the last month or so, as I've mentioned a few times before, I've been
trying to tidy up some of my older personal Emacs Lisp
packages. I thought I'd updated all the ones I commonly use, but it turns
out I hadn't. Somehow I'd missed
become.el.
This is another one of those packages whose content started out as ad-hoc
commands, added to the ~/.emacs that first started to emerge as I got to
know Emacs on OS/2 and then GNU/Linux back in the mid-1990s. I think it was
back in 20161, when I did a big revamp of my Emacs
environment, that I moved
all of those roughly-related commands out into their own file.
Honestly, I think I can dump most of them now. There's stuff in there for
quickly and easily converting buffers between "DOS format" and "Unix format"
(from back when I was still working a lot on Windows machines, and sometimes
even in MS-DOS-based virtual machines, and often using the
DJGPP-built version of Emacs).
One command I still use all the time is
become-free-of-trailing-whitespace, because I have that set up as part of
a before-save-hook:
While I know that there are better ways of handling the trailing space issue
these days, this is one I rolled for myself a couple of decades ago and it's
yet to fail me. You can see just how dated it is from this:
If you know, you'll know why is-sig-line is there2.
I do still use become-freshly-indented-no-tabs on occasion too, and have
it bound to an easy-to-remember and obvious (to me) key.
And so, despite the fact that most of the content of become.el is probably
obsolete at this point, despite the fact that there are probably far better
and more idiomatic ways of doing these things these days... it's my little
personal package that has grown with me in the 3 (and a bit) decades I've
had Emacs under my fingertips. I'm going to keep it around just a little
longer.
Marcin Borkowski (mbork) has a useful post on scrolling PDFs in the other window. He wants to use the familiar Ctrl+Meta+v and Ctrl+Meta+Shift+v shortcuts for pdf-tools. Sadly, these don’t work for scrolling PDFs but as mbork says, “… [I]t’s Emacs, so it shouldn’t be difficult…”. And, indeed, it isn’t.
His idea is simple. If the buffer in the other window isn’t a PDF, return nil. Otherwise simply call pdf-view-scroll-up-or-next-page or pdf-view-scroll-down-or-previous-page. Finally, he simply advises scroll-other-window and scroll-other-window-down to run his code first and skip the normal code unless his code returns nil. Take a look at his post for the code. As I said, it’s easy to understand.
The important takeaway from this, according to mbork, is how easy and understandable the solution is. The lesson, as it often is, is that if Emacs isn’t doing what you need, it’s usually pretty easy to make it do so.
Great news, everyone - CIDER 1.22 (“São Miguel”) is finally out!
And “finally” is the operative word here. This release took me way longer than
I wanted it to, but that’s because I decided to stop kicking a few cans down the
road and finally tackle some long-standing problems that had been bugging me for
years:
Session and connection management - the logic for figuring out which REPL a
buffer is associated with had grown into something I could barely follow myself.
The decoupling of nREPL from CIDER’s UI layer - a piece of technical debt so
old it predates most of you reading this (the tracking issue, #1099, is from 2017).
A full audit of the codebase and the documentation, hunting for
inconsistencies, dead code, broken menu entries, and gaps in the docs.
None of this is the kind of work that makes for a flashy release announcement,
but it’s exactly the kind of work that keeps a 14 year old project healthy. I
genuinely think this is one of the most important CIDER releases in recent
memory, even though most of the changes aren’t really user-visible.
Highlights
Picking a handful of items out of a very long changelog, here’s what I’d call
the highlights:
A huge editor responsiveness fix (#3933) - Clojure buffers no longer lag when there’s no REPL connected. The friendly-session matching used to scan the project classpath on every redisplay; now it does something far cheaper. If you’ve ever felt CIDER make your editing sluggish, this one’s for you.
Default sessions (#3865) - cider-set-default-session lets you bypass sesman’s project-based dispatch and pin a REPL as the default. Handy for all those workflows that never quite fit the project model.
nREPL is now decoupled from CIDER’s UI (#3892) - the transport layer no longer reaches into CIDER-specific handlers and UI strings. This finally closes #1099 and opens the door for other tools to build on our nREPL client.
Faster connection completions (#3888) - repeated cider-connect completions no longer re-spawn a round of ps/lsof subprocesses every single time.
A massive discoverability pass on menus and keybindings - menus across the inspector, REPL history, log, spec browser, and more now actually expose the commands they were missing (often a dozen+ per mode), and C-h m now lists the active bindings for several modes. A lot of functionality that was technically there but practically invisible is now front and center.
cider-repl-history-doctor (#3921) - a new command that walks your REPL history, finds entries with unbalanced parens, and helps you clean them up. Born out of a real bug report about history rendering breaking.
Support for let-go (#3926) - a Clojure dialect implemented in Go is now recognized as a known nREPL runtime.
Better remote (TRAMP) jack-in and connect (#3885, #3886, #3887) - endpoint detection, command resolution, and SSH tunneling all behave correctly against remote hosts now.
Plenty of nREPL robustness fixes - plugged several request-id leaks, bounded the completed-requests table, and made a misbehaving response handler no longer able to drop later responses on the floor.
Bumped the injected nREPL to 1.7.0 and cider-nrepl to 0.59.0.
The full list is much longer - check out the changelog if you want the gory details.
A fun little detour: Port and Neat
While I was doing the nREPL decoupling work, I got curious and started
experimenting with adding support for prepl
(Clojure’s built-in socket REPL) as an alternative to nREPL. I even put together
a prototype (cider#3899). It
sort of worked, but it also reaffirmed my belief that prepl and nREPL are
different enough that bolting prepl onto CIDER would mean papering over its
limitations in dozens of subtle places. So instead of forcing it, that little
experiment grew into two brand new projects of mine:
Neat - a tiny, deliberately language-agnostic nREPL client.
Both have write-ups of their own, so I won’t repeat the details here. I’m pretty
excited about where they might lead - a great example of how digging into old
technical debt can spark entirely new ideas.
Epilogue
This release is dedicated to São Miguel, the stunningly beautiful main island of
the Azores archipelago.1 I got a lot of my recent inspiration for CIDER there,
and naming the release after it felt right.
As always, none of this happens in a vacuum. A huge thank you to Alex Yakushev
for his continued work on the inspector - it keeps getting better and better. And
of course a massive shoutout to Clojurists Together
and to all the other contributors and backers of my open-source work. You’re the
reason CIDER and friends keep moving forward.
That’s all I have for you today. I hope you’ll enjoy using CIDER 1.22 as much as
I enjoyed (eventually) shipping it. Keep hacking!
If you ever get the chance to visit, do it. Crater lakes, hot springs, and the greenest hills you’ve ever seen. ↩
The simplification of my mode
line is sticking, in that I like
how it's turned out and I find it more useful to have it this simple. But I
did notice something was missing: I'm a pretty constant but pretty casual
user of projectile. I know it's a
package that offers a wealth of tools, yet mostly I just use it as a project
bookmark system. For this, though, it works well.
Given this, having a quick and easy way to check that I'm in the project I
think I'm in is a good idea. While I also have
neotree open all the time, which
gives a fairly obvious clue, my eyes keep flitting down to the mode line.
The change I made the other day, deliberately, left the project off. I think
this was a simplification too far. So now it's back.
A little busier than it started out, but still pretty clean. I do keep
wondering about the cursor position. In most buffers I have line numbers
showing to the left anyway, and it's rare (but not unknown) that I need to
know what column I'm in. I'm very tempted to remove the cursor position
altogether, then the right-hand side would just be the vc information, at
which point it might make sense to also move the project name over to the
right, given that the project and the repository information generally go
hand-in-hand.
I'll stick with this for now, but I can see this happening soon.
I have written about pdf-tools quite a few times – it’s a fantastic Emacs package for viewing and annotating pdfs without leaving the comfort of Emacs. It is not ideal, though – or at least, not ideal for me. One feature of Emacs I often use is the scroll-other-window command (bound to C-M-v), and its sibling scroll-other-window-down (C-M-S-v). They are extremely useful for example when reading documentation or watching live Markdown preview, and I wish they worked with the TeX and pdf-tools duo, too. Well, it’s Emacs, so it shouldn’t be difficult to make them!
It’s a pretty nice system but after using it for a while, Prot realized that when he was dealing with large directories a bit of initial filtering of the most recently modified files would be useful. He solved that by adapting his previous code to do the filtering. He does it by taking the list of files from his first function and running them through seq-filter to get the files he’s interested in. Again, all the code is in his post but Prot says he won’t be updating the post so you should check out his configuration for the latest version.
If you frequently generate Dired listings and would prefer to deal with a flat list of the files without worrying about what directory they’re in, take a look at Prot’s post for an excellent solution.
Update[2026-06-15 Mon 10:06]: Fixed link to Prot’s post.
Denote-journal, from the prolific Prot who also made Denote, was something I wanted to try for a while. I didn’t really have a good reason to, because I’ve been using Journelly for a long time, and on my Mac or Linux desktop, I’d call a capture template that would append to the file, adding my additional entries.
But I always had one major issue with journaling on my iPhone: privacy. My iPhone is owned and regulated (with a system profile) by my workplace. So even if I’m fine writing personal notes on my Mac (I’m not, I’m iffy about it as well, I don’t trust Apple to respect my privacy much more than I trust Google), at the end of the day, these notes also sync to my iPhone.
On a day-to-day basis, for quick thoughts and work notes, Journelly and my iPhone are great, but when it comes to writing longer notes about my future plans, how I spent the weekend with my partners, and basically anything else that involves people whose privacy I respect, I always self-censor.
For this reason, I came up with a way to create private notes with Denote only on Linux. These notes only live on my Linux Desktop, with a few of those syncing to my Android1 (again, not great, but at least it’s not work-managed).
I always feel more like myself on Linux because I am more myself - whether it’s customizing my shortcuts and workflow exactly how I like it, or if it’s the built-in privacy that can be further fortified and inspected. Journaling on Linux, without the world’s biggest nanny peeping over my shoulder, is where I really open up and write my most personal thoughts.
A couple of times I looked at my Journelly notes, those that I wrote on the Mac where I could write at length and use the full power of Emacs, and compared them to my older journal on Linux. Well, there is no comparison. And while creating a private note in Denote in Linux and linking it back to the original works2, it introduces friction that hinders the flow of my thoughts.
So I looked into denote-journal, realized it’s very easy to use, and gave it a try one day, and since then:
Essentially, it’s what I used to do when I started using Journelly: refile my Journelly headers into my journal files when I get the chance. Or, as a matter of fact, I use org-refile-copy, which does exactly what it says, because I want to keep the original in Journelly. Since I now use individual journal files instead of a big file split into weeks (as I did in the past), this process is even easier. The only catch is the images.
Images in Journelly are saved in its /Journelly.org.assets folder, where my journal files can’t see them directly; and even if it did, these images are too big and cause freezes, and also oriented the wrong way, so they need at least a minimal treatment. For these reasons, I attach each image to the correct header in the journal daily file which I moved over from Journelly.
These journal notes are fantastic. I have my quick notes from the day available, but when I want to extend, all I do now is just write a new entry for that day (which looks just like the Journelly entries) and write to my heart’s content. There’s also a bonus: denote-journal allows me to make up for days if I didn’t create a “meta journal note” for the day (so far this happened only once) directly from the calendar, so if I miss a day, I go to the calendar, point at the missing day, and use denote-journal-new-or-existing-entry to take care of things. If I already have an entry, it jumps to it; if I don’t, it creates one.
Between my journal on Linux, the emails I write to other bloggers, my blog posts, and the occasional instructions I write in Denote, I think I write more than I did in my entire life. I’m thinking I need to start capturing it in some sort of book, though I have no idea what it will be about and how to edit my writings in a way that makes sense. This is only a vague concept at the moment.
Footnotes
1 : I keep skirting around this issue so I’ll just mention it quickly: I used GrapheneOS in the past, and it’s great for these kinds of things, but GrapheneOS protects your phone to an extent that certain apps don’t work.
2 : I’ve been doing this often enough that I have a whole tag in Denote called “supplemental” with additional thoughts and notes. In Journelly, I was just linking to those, and writing something like “I have more to say about this” and this would include a Denote link to the Linux-only note.
I've released blogmore.el v5.3.0.
This is a pretty small release but adds a command I realised I'd forgotten
to add a couple of releases ago.
Now that BlogMore has the concept of a post
series, and now that blogmore.el lets you add and remove a series from a
post, it makes sense that I'd want to link to a series in a post from time
to time, like I can and do with categories and tags.
So v5.3.0 adds a blogmore-link-series command. It can also be found in the
transient menu.
Emacs features have a discoverability problem, and we’re chipping away at it one
demo at a time. The years since I wrote the last one of these have yielded more
surprising and useful finds, so it’s time again for a “batteries included”
report.
Note
This is the third in a series of articles highlighting useful but lesser-known
features included in Emacs.
“Lesser-known” is a subjective judgment. Roughly, it means that at the time of
writing, I have seen these features mentioned fewer than five times – and often
never – in the past two decades of dipping in and out of online Emacs
discourse. Some of the features covered in past entries are well known and
often recommended today. I claim no credit.
If you’re a new Emacs user, don’t start here. This is not a getting-started
guide. You will be better served by grokking basic Emacs concepts and sticking
to the most widely recommended packages. Once you’ve experienced the Emacs
equivalents of thoughts like “Why didn’t anyone think to put wheels on luggage
until 1990?”, this series might be more helpful.
My rule of thumb is that if you aren’t yet aware of undo-in-region, there is
much low hanging fruit for the picking, and you can come back to this article
after that supply has run out!
.
Veteran Emacs users tend to use some relatively niche Emacs features, but in my
experience it’s always a different subset for each user. So if you’ve been
around the block a few times, I promise there will still be surprises below for
you as well!
Same rules as before:
No packages, stock Emacs only
No steep learning curves. Learn each feature in under five minutes or bust.
No gimmicks. No doctor, tetris, snake, dunnet, zone,
butterfly… yes, we know about dissociated-press. Let’s move on.
Just the deltas. No commonly mentioned packages like Flymake, doc-view,
outline-minor-mode, gnus or eww. Nothing that Emacs brings up automatically or
a nonspecific Google search gets you.
Assume a modern Emacs, 28.1+.
Also, if you’re new to Emacs and still reading:
Emacs jargon
Modern parlance
M-x
Alt + x
C-x
Ctrl + x
Frame
Emacs window
Window
split/pane
Buffer
Contiguous chunk of text/data
Point
Cursor position in buffer
Active Region
Text selection
Region
Text selection (not highlighted)
Face
Font, color and display properties
I’m Sorry.
Okay? Let’s go:
Dictionary on hover (M-x dictionary-tooltip-mode)
Turn on dictionary-tooltip-mode to see word meanings in tooltips when you
hover over them:
Of course, tooltip-mode will need to be enabled as well, but that’s the
default.
If you have local dictionaries set up, it will try those first. Note that
Emacs’ dictionary can look up contemporary jargon and lingo too, usually via
Wiktionary:
find-file and dired with wildcards
A surprisingly little known utility of two of the most used Emacs commands: you
can use wildcards when using both find-file and dired interactively.
When finding files with find-file (C-x C-f), open multiple files at once
with a wildcard like *foo*.txt.
When opening a directory with Dired, produce a custom listing of specific
files by specifying a filename wildcard.
Here’s a demo where both features are used to clean up some (very) old TeX
compilation artifacts and then open a bunch of LaTeX files at once:
Play by play
Run Dired with a “two-level” wildcard */*_region_*: look for all files with
"_region_" in their name, but only in sub-directories.
Dired produces a listing of these files. (These are temporary files created by
AucTeX.)
Select them all (with dired-toggle-marks, bound to t) and delete them.
Run find-file with a wildcard, opening all TeX files in sub-directories.
Check the list of buffers to see that several TeX files have been opened.
(The command used to see the list of open buffers is consult-buffer, and the
completions are displayed by Corfu.)
The fact that this is possible when calling them programmatically is evident
from their function signatures. But realizing that this capability is also
available during interactive use requires reading through the full docstring,
and no one has the time for that!
In practice the Dired wildcard capability is superseded by a modern workflow
like consult-find exported as a Dired buffer by embark-export, but this
works out of the box.
List all URIs with M-x ffap-menu
You might be familiar with Emacs’ “find-file-at-point” feature, M-x ffap, that
checks if the cursor is on a valid file path and offers to open it.
This is accompanied by ffap-menu, a less well known but equally handy command.
ffap-menu scans the whole buffer for anything that looks like a file path or
URL and presents you with all of them:
Since it offers a completing-read interface, this opens up a small universe of
possibilities: you can export the list of (possibly filtered) completions into a
buffer, copy or open all or any subset of them, or otherwise act on them right
away with Embark.
Addendum: Listing propertized links
Many Emacs applications (like EWW) include URLs as text properties and not
plain-text links, and ffap-menu misses them. Inspired by ffap-menu, I use a
home-brew version that fetches such links as well.
Play by play
Start with EWW showing a Wikipedia page, with imenu on the left.
Call my/search-occur-browse-url, a custom command inspired by ffap-menu
Scroll through the list of page links, and scroll through the page itself.
The enhanced version:
Searching for all URLs in the buffer
(defunmy/search-occur-browse-url (&optionaluse-generic-p)
"Point browser at a URL in the buffer using completion.
Which web browser to use depends on the value of the variable
`browse-url-browser-function'.
Also see `my/search-occur-url'." (interactive"P")
(let ((matchnil)
(match-datanil)
(context (lambda (beg&optionalshrp)
(let* ((before (string-replace"\n""" (buffer-substring-no-propertiesbeg (max (line-beginning-position) (-beg30)))))
(link (string-replace"\n""" (buffer-substring-no-propertiesbeg (point))))
(after (buffer-substring-no-properties (point) (min (line-end-position) (+ (point) 30)))))
(concat (propertize" "'display'(space:align-to65))
(propertize (concat"…"before) 'face'shadow)
(ifshrp (propertizelink'face'(:inheritshadow:weightbold:underlinet))
link)
(propertize (concatafter"…") 'face'shadow))))))
(save-excursion (goto-char (point-min))
(while (search-forward-regexpmy/search-url-regexpnilt)
(push (cons (match-string-no-properties0)
(funcallcontext (match-beginning0)))
match-data))
(goto-char (point-min))
(while (setqmatch (text-property-search-forward'shr-urlnilnil))
(push (cons (prop-match-valuematch)
(funcallcontext (prop-match-beginningmatch) 'shrp))
match-data)))
(let* ((completion-extra-properties`(:annotation-function,(lambda (cand) (concat" " (cdr (assoccandmatch-data))))))
(url (completing-read"Browse URL: "match-datanilt)))
(ifuse-generic-p (browse-url-genericurl)
(browse-urlurl)))))
Compare windows (M-x compare-windows)
There are more commands for comparing buffers and files in Emacs than you can
shake a stick at: there’s diff, diff-buffers, diff-backup,
diff-buffer-with-file, dired-diff, vc-diff, and a whole constellation of
ediff-, ediff-merge- and ediff-directories- commands. I lost count at
around twenty two, and can’t remember most of them.
But my favorite diff command is the lightweight compare-windows, which does
something very obvious and simple in a context-agnostic way.
It compares the text of two windows starting from their respective cursor
positions, and stops at and reports the next mismatch. The two windows are the
active one and whatever other-window would select. Obviously less powerful,
but so much easier and faster to run than Ediff
Have you tried ediff-regions-linewise? Setting this up is a four step
process, involving selecting buffers, marking regions and calling
exit-recursive-edit repeatedly, an advanced command that most Emacs users
should never encounter!
or diff:
Play by play
Move the cursor to the beginnings of the text to compare in two windows.
M-x compare-windows
That’s it. It moves the cursors to the first mismatch and reports it.
compare-windows is only concerned with the actual text in the two windows, and
not the provenance of this text. The buffer type, modification state, file,
version-control status – all irrelevant! You can even compare a
chunk of text in a buffer against another chunk a little further down in the
same buffer by displaying it in both windows. In a silly yet effective way, it
can even compare directory contents, including file attributes:
Play by play
Two directories containing some similar-looking files.
Place the cursors on the same file in both windows.
M-x compare-windows
The cursors stop at the first reported mismatch, which is a file modification
time here.
And yes, you can call it with a prefix argument to ignore whitespace differences.
compare-windows is what you use when you find yourself playing
spot-the-difference between two views of any kind. It is my most used “diff”
command.
Compare directories with Dired (M-x dired-compare-directories)
But speaking of comparing directories, Dired does (of course) provide a less
hacky way to do that. M-x dired-compare-directories in Dired prompts for a
directory to compare with, and marks all files whose names differ in both Dired
listings. That covers the most common use case, and might be everything you
need.
But we already did that with the rudimentary compare-windows.
dired-compare-directories is an actual file-level comparison, so you can
provide custom matching predicates involving any file attribute, like
modification times or sizes. For instance,
you can mark the more recently modified version of a file with (> mtime2 mtime1),
or mark files with the same name but different sizes with (/= size1 size2)
In this example, dired-compare-directories has marked (i) files that are not
common to the two listings and (ii) files with differing modification times:
An Ediff for every season
If you want something more interactive/prescribed there is also an
ediff-directories, because there is an Ediff command for every occasion.
While we’re on the topic of spotting differences, highlight-changes-mode is a
handy way to emphasize changes to the file, and a “live” alternative to diff
commands like diff-buffer-with-file:
Play by play
Run the below code block syncing highlight-changes-mode with save-buffer.
Now changes are highlighted until the next save.
Make some changes. Notice that added/changed text is colored differently.
Save the buffer, clearing the highlights in the process.
Repeat the last two steps a couple of times.
Visualization with highlight-changes is determined only by the mode itself, and
changes are highlighted from the time the mode is turned on until it’s turned
off. In general, this is not what we want. What we would like instead is to
highlight unsaved changes
There is M-x highlight-compare-with-file, but this is non-ergonomic enough to
the point of being unusable.
. We could do this with some finesse, or just throw in a couple of hooks:
Now all changes in text-mode buffers are automatically highlighted.
highlight-unsaved as a standalone feature
The highlight-changes visualization can be customized to be more subtle, but you
probably don’t want it turned on all the time nevertheless. The above hook
logic can easily be turned into a minor-mode in its own right:
(require'hilit-chg)
(defunhighlight-changes-mode-turn-off ()
(andhighlight-changes-mode (highlight-changes-mode-1)))
(define-minor-modehighlight-unsaved-mode"Highlight all changes until the buffer is saved.":lighter"H" (cond ((not (buffer-file-name))
(user-error"Highlight-until-save-mode is only meant for use in file-visiting buffers"))
(highlight-until-save-mode (highlight-changes-mode1)
(add-hook'after-save-hook#'highlight-changes-mode-turn-onnilt)
(add-hook'before-save-hook#'highlight-changes-mode-turn-offnilt))
(t (highlight-changes-mode-1)
(remove-hook'after-save-hook#'highlight-changes-mode-turn-ont)
(remove-hook'before-save-hook#'highlight-changes-mode-turn-offt))))
Finally, highlight-changes-mode provides an auxiliary capability: you can jump
to the next and previous change in the buffer with
highlight-changes-next-change and highlight-changes-previous-change. Since
this is an independent consequence of change tracking you can use just this
navigation and turn off the change visualization with M-x highlight-changes-remove-highlight.
Actually useful file backups (vc-diff variants)
One last excursion to close out the theme of spotting and diffing changes.
This will require a tangent through the topic of Emacs backup files and is
pushing both the five minute limit and the idea of a built-in, so please bear
with me.
Let’s back up
By default, Emacs makes a periodic backup of any file you edit and save.
This backup system is usually mentioned only in the context of being something
annoying you should disable (via make-backup-files). If you want actual
backups you could just use version control, right?
If you have security concerns with sensitive files being copied to elsewhere on
disk, I sympathize. But otherwise, I think this is largely an ergonomics issue.
Emacs litters your working directory with the backups, and
doesn’t make it easy to peruse and work with the backup files.
Changing the former is a user option
For example, see backup-directory-alist, kept-old-versions and
kept-new-versions.
, but the latter is entirely the case of a missing user interface.
The external package backup-walker provides this “time-machine” interface,
along with a couple of others. But there is a simpler, satisfying fix available
that simultaneously solves another problem.
VC (until V don’t)
Emacs’ built-in VC package offers an interface for viewing past versions of
version-controlled files:
vc-diff (C-x v =)
Diffs the file against its immediate previous
version, or against a prescribed version when called with a prefix argument.
vc-ediff
Runs Ediff against the file’s previous version, or against a
prescribed version.
vc-revision-other-window (C-x v ~)
Displays a previous version (immediate or
specified) of the file next to this one.
This is a handy interface
and not git-specific, unlike magit’s versions of these commands.
, but of course they do nothing in files that aren’t version controlled.
In the spirit of getting the most out of every fiber of muscle memory, we can
extend the vc- interface for the purpose of inspecting backups as well.
The bridge
We can overload all three VC commands so they always do something useful in a
file:
If the file is unsaved, vc-diff (vc-ediff) generates a diff of (runs Ediff
on) the buffer against the file.
If the file is version controlled, run vc-diff (vc-ediff,
vc-revision-other-window) as usual.
If the file is not version controlled, diff against (Ediff, show) the latest
numbered backup, or a prescribed numbered backup when called with a prefix
argument.
This forces functions into a single consistent mental model:
Compare against the previous version, for whatever “previous” means in this
context.
As a bonus, we are also free to forget about a few different diff commands that
have been subsumed here, such as diff-buffer-with-file and ediff-current-file.
Augmenting vc-* commands
(defunmy/read-backup-file-name (file)
(if-let* ((backup-files (file-backup-file-namesfile)))
(completing-read"Backup version: "backup-filesnilt)
(user-error"No backup files available for file %s" (buffer-file-name))))
(defunmy/vc-diff (&optionalarg)
"Compare current buffer with its file, or file with backup or revision.
With prefix ARG, compare the file with a selected backup when the file
is not under version control." (interactive"P")
(if (buffer-modified-p)
(diff-buffer-with-file (current-buffer))
(condition-caseerrdata (call-interactively#'vc-diff)
(error (if (string-match-p"not under version control" (cadrerrdata))
(ifarg (diff (my/read-backup-file-name (buffer-file-name))
(buffer-file-name))
(diff-backup (buffer-file-name)))
(apply#'signalerrdata))))))
(defunmy/vc-ediff (&optionalarg)
"Run Ediff on the current buffer, file, or backup.
With prefix ARG, compare the file with a selected backup when the file
is not under version control." (interactive"P")
(if (buffer-modified-p)
(call-interactively#'ediff-current-file)
(condition-caseerrdata (call-interactively#'vc-ediff)
(error (if (string-match-p"not under version control" (cadrerrdata))
(ifarg (ediff-files (my/read-backup-file-name (buffer-file-name))
(buffer-file-name))
(ediff-backup (buffer-file-name)))
(apply#'signalerrdata))))))
(defunmy/vc-revision-other-window (&optionalarg)
"Visit the current file's past revision or backup in another window.
With prefix ARG, visit a selected backup when the file is not under
version control." (interactive"P")
(condition-caseerrdata (call-interactively#'vc-revision-other-window)
(error (if (string-match-p"not under version control" (cadrerrdata))
(ifarg (find-file-other-window (my/read-backup-file-name (buffer-file-name)))
(if-let* ((backup (file-newest-backup (buffer-file-name))))
(find-file-other-windowbackup)
(user-error"No backup files available for %s" (buffer-file-name))))
(apply#'signalerrdata)))))
See scroll all windows for a demonstration of the
generalized vc-diff working with backup files.
The apropos family
If you only use one help keybinding, it should be C-h k, describe-key, since
the very fact that every key press invokes a first-class function that you can
live-inspect and mess with can be a revelation.
If you learn two, there is a strong case for apropos being the second. It
bridges the gap between not knowing what to search for and getting a full
picture of how things are laid out. It’s a foot-in-the-door command.
But you already know apropos. What’s less evident is that apropos is a
whole family of commands that do increasingly specialized but useful look-ups
It’s ironic that the extended apropos family is itself not very discoverable.
.
Bind them all under C-h a, replacing apropos:
(defvar-keymaphelp-apropos-map:doc"Keymap for apropos subcommands.""a"#'apropos"l"#'apropos-library"f"#'apropos-function"x"#'apropos-command"v"#'apropos-variable"V"#'apropos-local-variable"u"#'apropos-user-option"d"#'apropos-documentation"C-f"#'customize-apropos-faces"g"#'customize-apropos-groups"o"#'customize-apropos-options"c"#'customize-apropos"i"#'info-apropos)
(keymap-sethelp-map"a"help-apropos-map)
prefix-help-command
You don’t need to remember any of these! If you don’t already use a prompter like
which-key, you can press C-h after the prefix C-h a to bring up a listing of the
available commands.
My favorite of these is customize-apropos: it produces a bespoke customization
buffer for perusing or changing all options matching the thing you searched for:
Play by play
Invoke the apropos map prefix (C-h a)
Press C-h to see available commands under this prefix. I used Embark for
this feature, but you should see a list of available commands no matter what.
Pick customize-apropos and search for “async”
It produces a customize buffer with all options, faces and groups matching “async”.
One of the most useful things you can do in Emacs, if you don’t like what a
keybinding does (or if you’re simply curious), is to jump to the definition of
the command it calls to see how to modify its behavior live. Normally this is a
multi-step process:
Find the command invoked by the key: describe-key or C-h k + your key
sequence.
Jump to its definition by pressing s (for “source”).
Get hacking or reading.
find-function-on-key obviates step 2, and takes you from keybinding to the
source. Bind it to a key and you’re off to the races.
C-h M-k for me, as it’s a variation of describe-key:
(keymap-sethelp-map"M-k"#'find-function-on-key)
Going from a keybinding to the source of the function in one step is a minor
shortcut for the common route, but it’s magical the first time you try it.
No video demo, because the effect is so instantaneous a video would be both (i)
confusing and (ii) underwhelming!
copy-from-above-command and duplicate-dwim
Emacs recently added some missing editing commands that have been part of most
users’ tool-belts for decades. The two most useful of these are for duplicating
text with the cursor as the destination and source. Respectively,
copy-from-above-command copies text from the first non-blank line above the
current one, similar to Vim’s C-y.
duplicate-dwim copies text on the current line (or active region) below the
current one, similar to Vim’s yy<N>p1.
In typical Emacs fashion, slight tweaks can make these commands work how your
brain does:
copy-from-above-command copies as many characters from the above line as the
prefix argument. I typically want to copy the whole line, so I change the
prefix argument interpretation to “copy the above line and comment it out”, a
very common action when experimenting with code or prose:
Note that the original prefix argument behavior still works, and you can copy
a fixed number of characters from above with a numeric prefix argument
(C-<N>).
duplicate-dwim has a choice to make about where to place the cursor after
the duplication: does the user mean to continue working with the duplicated
text or the original?
You can make that choice for yourself by setting a user option. I prefer to
move the cursor and region to the duplicated text:
Turn keystrokes into macros (M-x kmacro-edit-lossage)
Three facts about Emacs keyboard macros:
They are far more powerful than many users realize
See Mickey Peterson’s excellent article Keyboard Macros are Misunderstood
. We tend to associate macros with text transformations, but they capture
and playback any sequence of actions in Emacs, including mouse clicks. And
since this is Emacs, actions don’t have to correspond to text editing at all.
All the short video demos in this article were copied across Dired buffers,
processed with FFmpeg, renamed and inserted into the draft using a single
keyboard macro.
They require a lot of premeditation and focus to use. Unfortunately
“thinking in macros” is cognitively taxing. Any error or non-generalizable
movement can scupper the whole attempt. The multiple-cursors package and
others like it present alternative interfaces to keyboard macros that lower
the mental strain.
But they still don’t solve the “foresight” problem: I need to know before the
fact that a sequence of actions will need to be repeatable, and start a
recording. Coupled with the fact that you’re unlikely to get a complex
sequence right the first time, we’re back to the previous problem again.
Vim’s . (dot) command is a solution here, since Vim is effectively
always recording a macro of your edits, and Emacs’ dot-mode package emulates this
with some success. But these are still limited to buffer edits, and not full
fledged keyboard macros.
Well. Emacs provides the confusingly named kmacro-edit-lossage command that
addresses this foresight problem, albeit in a manual way. At any time, you can
view your “lossage”, a record of the last 300 or so key-presses with the
view-lossage (C-h l) command.
kmacro-edit-lossage takes this further, and lets you create a macro from your
key-press history at any time. The lossage is truly editable, you can and will
want to insert new commands into the lossage when creating a macro. An example
of creating a macro from a keystroke sequence that is setting up a window split:
“Oh, I need to do the complex thing I just did 200 times”
In practice, I edit macros I’ve already defined with edit-kbd-macro (C-x C-k e) more than I fashion new ones from the lossage, but on the infrequent
occasions that call for kmacro-edit-lossage, it’s a real lifesaver
The editing process generally requires a generous sprinkling of
kbd-macro-query calls into the lossage to be truly generalizable.
.
subword-mode, superword-mode and word syntax
Emacs offers word-based navigation and editing commands (forward-word,
forward-to-word, kill-word…) and major-mode-specific syntax tables,
leaving the question of “what is a word?” up to you.
subword-mode and superword-mode are two different answers to this
question. With subword-mode turned on, each component of a CamelCase symbol
counts as a word. As the documentation helpfully illustrates:
When superword-mode is turned on, snake_case symbols like this_is_a_symbol
counts as one word
The string-inflection package provides a command to easily cycle between these
styles: this_is_a_symbol –> this-is-a-symbol –> This_Is_A_Symbol –>
thisIsASymbol –> ThisIsASymbol.
. In practice, this is less useful than subword-mode, since acting on
symbols is already well supported in Emacs via the *-sexp commands.
More generally, it can be worth taking a few minutes to modify the syntax table
of a major mode to fix annoyances you might be experiencing with structural
navigation. In Lisp-y contexts, my most useful change is to make “:” be
considered part of a word, so that I can backward-kill-word through keywords
like :foo:
See describe-syntax (C-h s) and modify-syntax-entry for how to specify the
syntax of characters.
Manipulate image display
Almost everywhere that Emacs displays an image, you can manipulate the display
by placing the cursor on the image and pressing i. Here is an example with
images displayed in Elfeed (an RSS feed reader) and in Org mode:
Play by play
Preview an Org mode link to an image with org-link-preview
Zoom in with i +.
Subsequent zooms and rotation don’t require the i prefix because I use repeat-mode.
Do the same to the image displayed in the Elfeed entry buffer.
I used the keyboard in this demo, but you could just use the C-<wheel>
shortcut familiar from browsers and other applications.
The most useful bindings are i + and i - to zoom, and maybe i r to rotate the
image by 90 degrees. But you can do other things like cropping the image with i c – see
M-x describe-keymap⮐ image-map.
If you use repeat-mode, you don’t need the i prefix after the first invocation
either, you can repeat with just +, - or r.
This functionality is provided via a keymap placed over images, and nothing
needs to be turned on for this. Note that only the image display is modified,
not the image on disk.
In web-pages and rendered-HTML buffers, there is one more useful command:
pressing z (shr-zoom-image) will split the image into horizontal strips
across several lines, and cycle through different image sizes. It’s an odd
command, probably intended to mitigate Emacs’ display engine limitations when
dealing with large images. But mitigate it does. Useful if you visit websites
with huge images in Emacs.
Make all text visible (M-x visible-mode)
Emacs can make buffer text selectively invisible. Marking text as invisible is
the basis of all “folding” behavior – think magit-section buffers, Outline
mode, Org mode and so on. Every mode that provides folding also provides
keybindings to toggle the fold state, and pressing TAB usually works.
Usually.
In practice, these keybindings tend to be all over the place. For when you
can’t be bothered to learn mode-specific conventions because you don’t use the
mode enough
Or because the interface is bonkers, like the default outline-minor-mode keybindings.
and just want to see all hidden text, you’ve got visible-mode.
Play by play
In a buffer with outline-minor-mode enabled, run visible-mode. All text
is revealed.
Run visible-mode again to restore the previous text invisibilty state.
Switch to a magit buffer and run visible-mode for similar effects.
visible-mode is somewhat low-level, it simply disables text invisibility
across the buffer until you call it again. So if the buffer is presenting a
“reactive” UI where (un)folding text has dynamic effects, things can appear
broken until you disable visible-mode. As such, it’s intended as a temporary
measure or a debugging tool, but since it always works it’s my go-to button
for showing all buffer text uniformly with one command.
Ignore invisible text (isearch-toggle-invisible)
And speaking of visible-mode, some Emacs commands like Isearch ignore
text invisibility out of the box, making it easy to search across the actual
document text
As usual, the full behavior is more complicated. Isearch also restores the
invisibility when you move out of an invisible region that was temporarily
revealed.
.
But this behavior also has a downside. When the buffer as presented is intended
as a guide, automatically revealing invisible text breaks our assumptions about
what Isearch will do. This is a problem when using Isearch as a navigation (and
not a search) tool.
You can toggle searching invisible text when using Isearch with
isearch-toggle-invisible, bound to M-s i when searching:
Play by play
With the intent to jump to one of the last headings in this Org document, Isearch for “zero”.
The search skips to a match in a folded region instead.
Cancel the match with isearch-abort (C-g)
Start Isearch again, and run isearch-toggle-invisible (M-s i)
Search for “zero”, jumping only to matches in the visible text
Exit Isearch at the desired match.
This keybinding is not arbitrary – all the Isearch behavior toggles are under
the M-s keymap, mirroring Isearch’s default binding of C-s. (But that’s a
whole article unto itself.)
Ruler (M-x ruler-mode)
At some point in its eventful past, Emacs was intended to possess WYSIWYG
word-processing features. This is not surprising, it’s difficult to find
computing applications that Emacs doesn’t implement in its own janky, special
way.
One of the byproducts of this ambition is that there are some semi-buried
WYSIWYG features lingering around. The center- commands are one such feature,
centering lines, paragraphs and regions relative to fill-column. Useful for
fancy comments in code… and not much else, unless you like to print from Emacs
buffers.
But customizable display margin and fringe widths are a welcome addition, as a
lot of functionality can be stuffed into this screen estate. The only problem
with specifying widths like margins is actually doing it.
You might think that the handily named set-left-margin and set-right-margin
commands do this, but they actually work like the center commands, indenting
the actual buffer text.
It’s surprisingly messy. There is no direct command for this, and setting the
display margins does not take effect until the window is displayed again.
ruler-mode has you covered:
Play by Play
Turn on ruler-mode.
Hover over the header-line for a tooltip with instructions.
Use S-<mouse-1> and S-<mouse-3> to set the left and right margin for the buffer.
Drag <mouse-2> to set the fill-column.
Fill a paragraph to demonstrate the changed fill-column.
Restore the margins and turn off ruler-mode.
As a bonus you can set the fill-column too.
You can also set the goal column, but that’ll have to wait.
Of course, you could use the visual-fill-column or olivetti packages for
this, but if you like to change the margins on the fly instead of toggling
between preset widths, ruler-mode is arguably even more user-friendly.
Refill text (M-x refill-mode)
On the theme of text widths, Emacs provides a handy series of fill- commands
and an auto-fill-mode for filling text as you type.
The fact that auto-fill-mode features prominently in Emacs’ tutorial,
among the first things you’re expected to learn, suggests that Emacs takes
text filling very seriously, considering it a crucial text-editing feature.
Personally, the only people I know devoting any of their attention to text
widths on computer screens are professional typesetters… and some Emacs users.
If you’re reading this you might be one of them, so I ask you: isn’t it odd that
auto-fill-mode is not actually automatic? It only wraps the line you’re on,
leaving any earlier misalignment in the paragraph (caused by pasting text from
elsewhere, say) to be fixed manually.
refill-mode is Emacs’ actual automatic text-filling feature. It ensures that
your document stays wrapped at the fill-column:
M-x refill-mode and you’re set.
Scroll all windows (M-x scroll-all-mode)
There are two commonly recommended scroll-related commands that new Emacs users
find surprising, in the sense that they make you wonder why other software
doesn’t have them.
The first is scroll-other-window, for scrolling the window that isn’t selected
without having to switch to it first. This is very handy when the next window
contains material that’s a reference for our work in this one. The second is
follow-mode (covered in an earlier installment), giving you a contiguous view
of a single buffer across multiple windows.
scroll-all-mode is almost as useful, but lesser known than these two. This
mode scrolls all windows on the frame simultaneously: very handy when you’re
looking at buffers that need to be “synced” in some way. A common use for me is
eyeballing two versions of a file without having to get locked into an Ediff
session:
Play by play
Open a specific previous backup of the current file with
vc-revision-other-window (actually my spin on it, covered above)
Turn on scroll-all-mode
Scroll the window as usual. All windows scroll simultaneously.
It’s just M-x scroll-all-mode.
Bonus: scrolling other windows and master-mode
While we’re on the topic of scrolling other windows, a common question is what
happens if you have more than two windows on screen, and the window you want to
scroll is not the “next-window” that Emacs picks
This tip is recycled from The Emacs Window Management Almanac, but I wouldn’t
blame you for missing it in a 15,000 word sea of blather.
.
One solution is the built-in master-mode, where you can pre-designate (or
live-designate) buffers that should be scrollable from other buffers.
But a more immediately useful method is to set the strategy used to find the
window to scroll. One option is
(setqother-window-scroll-default#'get-lru-window)
which will always scroll the least-recently-used window. This is useful if the
window you want to scroll contains reference material that you won’t be editing,
so the window will rarely be selected.
Alternatively, you might have two windows (of many), both of which see frequent
edits. You’d then use the most-recently-used window as the other window to scroll:
(setqother-window-scroll-default (lambda ()
(or (get-mru-windownilnil'not-this-one-dummy)
(next-window) ;fall back to next window (next-windownilnil'visible))))
Some combination of these should make scroll-other-window always
do-what-you-mean.
Refuse to terminate (M-x emacs-lock-mode)
If you try to quit Emacs with unsaved files, Emacs refuses until you answer the
question of what to do about each of them. Annoying perhaps, but a useful
check.
emacs-lock-mode extends this idea and hands you the controls. Call it in any
buffer to “lock” it.
Until the lock is disengaged, the buffer will refuse to be killed, throwing up a
message instead:
Buffer "*scratch*" is locked and cannot be killed
and Emacs will refuse to exit:
Emacs cannot exit because buffer "*scratch*" is locked
This is handy for non-file-visiting buffers containing information you don’t
want to accidentally lose, or just as a reminder that a task in that buffer is
pending, and you shouldn’t throw away the context.
In a post Org-capture world, the former is rarely an issue, but locking is still
useful in shell and compilation buffers, websites or other special applications
that contain output or state you don’t want to lose.
Undelete frames (M-x undelete-frame-mode and M-x undelete-frame)
If you accidentally close an Emacs frame with a carefully curated workspace,
M-x undelete-frame has your back. Uh, if you’ve turned on
undelete-frame-mode, that is.
It does exactly what the more widely recommended (also built-in) winner and
tab-bar-history packages do, but for frames instead of windows. Turn on
undelete-frame-mode with your Emacs and don’t worry about closing frames
again. It can restore up to the last 16 deleted frames.
The leftovers
That’s twenty Emacs features I collided with in the last six years that have
survived contact with the reality of using Emacs in 2026. Several more Emacs
libraries discovered by fat-fingering the keyboard ended up being more
interesting as archaeological artifacts than as reliable solutions to common
user needs. allout-mode is Org mode from a parallel universe, an outline
manager with features like Org’s speed-keys and even per-subtree encryption.
shadowfile is implementing unison from inside Emacs, with questionable
utility. double-mode is a key-translation-based input-method for typing
non-keyboard characters that predates quail. The bs library was someone’s
attempt at a smarter list-buffers command, but ibuffer blew everything else
out of the water so there’s no reason to use it.
Other ostensibly handy features, like wrapping regions with delimiters using
electric-pair-mode, didn’t make the cut because the ratio of finickiness to
utility is too high. It’s better to just use an external package like
wrap-region, smartparens or embrace for this.
Then there’s the constellation of included Org and Org-adjacent libraries (like
appt) that add interesting but obscure features to Org mode. But that’s an
expansive story, best covered in a dedicated article.
Finally, a lot of my serendipitous finds were libraries new and old that
are primarily of interest to Elisp developers. The thunk library is an
example of this. These too deserve their own write-up.
Still, I hope you found at least a couple of useful tips among the batteries
that passed testing. The lisp directory that ships with Emacs isn’t that big,
but somehow this barrel never runs dry. I don’t doubt that more batteries
remain to be found, even if it takes me a few more years of typos to stumble
onto them. Until then, happy Emacsing!
A mini rant: This is your cue to tell me that yyp
is not a Vim command but a shining example of its command composition
language, where yy and p do different things. And mine to tell you that no
Vim user, including you or me, thinks about an exceedingly common action like
yyp this way in practice. Your fingers memorized the sequence years ago and
carry it out before you can muster the wherewithal to consider that you are
composing a yank and a paste. It’s simply not a high-level cognitive action, so
this is a distinction without a difference. ↩︎
I have been thinking of Separate Writing and Formatting. This is an interesting discourse on the need to separate the acts of writing from the act of preparing to present. I agree with the premise.
The Notion of a Canvas
Conceptually I look on the task of writing as starting with a blank canvas. The words then come in and fill the page. I don’t think of how it will look on the final document. Most of the time, I don’t care for the output. It is going to remain a text document in the Org format or Markdown format, depending on what I need.
The Different Types of Writing
I do two kinds of writing. The first kind is stream of consciousness writing. I have some idea of the topic and I type. I don’t know the topic completely, or don’t know how I feel about it. It is the act of writing that sheds light on my opinions or feelings. It is a dialog with myself. There is not much structure to it, but there is the belief that structure will come. After I have exhausted my exposition of the idea/topic on the page do I go through the task of editing and structuring. I like this process.
The second kind of writing I do is when I start with the structure. I think this is dependent on the topic I am writing on. If I know the topic well or have clearly formed ideas about the topic does this kind of writing work. I start with the structure. The structure leads me to the nature of the argument I am making. Once I have the structure laid out, I fill in the meat to the structure by writing it out. This process seems to lead to two diverse results. The structure changes. The argument flows differently. Most of the time, the arguments become more nuanced. Very few things in life are black or white. The calibration of the argument leads to nuances and an abundance of grays.
Most of the time, the writing happens in Emacs. Org-mode in Emacs. That has the advantage of being conducive to structure or the lack of it.
I notice that I like switching the applications around without any conscious thought. Sometimes, like this document I am working on, it starts as an OmniOutliner document. When I am done with it, this is going to get exported to a plain text file. It is going to be opened in Emacs for a look through or iA Writer for editing. Only after that will it be exported to the format I need to share (Markdown, PDF, Word, or HTML).
Necessary Conditions
I want the document to be full-screen. I don’t want distractions.
I want typewriter scrolling. I hate looking at the bottom of the screen all the time when I write.
I want to be able to focus on sections/paragraphs when I write.
OmniOutliner has the ability to let me focus on sections of the document. It lets me reduce the noise and concentrate on a section of the document and ignore everything else. I can concentrate on writing a particular section and not be affected by the others. iA Writer has the ability to focus on a paragraph or on a sentence, and I have been using that for a long time.
In Emacs, I can achieve the same effect by calling a function recursive-narrow-or-widen-dwim. It performs the same task of narrowing my focus to the section that I am writing. Call it again, and you are back to the whole document. This is from the package Recursive Narrow.
They are Separate
The act of writing and the act of organizing the writing are separate activities. I find myself more productive when I am conscious of the separation and make sure that I am not allowing one to bleed into the other. Obviously during the editing phase, it becomes one. The act of structuring the argument leads to both changes to the structure and some changes to the nature of the content. This is my writing process.
The iA Folks
The iA folks make the argument that writing and formatting should be different steps. I have no disagreement with that view. I think the process of writing, structuring, editing, and formatting are all better off being different steps. Those are separate functions and my writing improves when I am conscious of that.
Is Writing Hard?
Thinking is hard. Writing is thinking. So writing is hard.
This is not prophetic. Everyone knows this. The question which is relevant here is how do you make it easier?
I don’t have the answer.
I made it easier for myself by sticking to a process. Whatever process you are comfortable with and have repeated success with is the cure to your problem with writing. It is not the same for everyone. Nor is the same process the most efficient for the same person all the time. That is the logic behind me relying on a mixture of applications to produce my writing. It works for me. Your mileage may vary.
Presentation is Integral to Influence
Presentation of any kind of writing is a crucial part of the process of influence. Structure and Formatting are elements of that effort. I must admit that I am not an expert in this field. In other words, I have no idea how to make a document look persuasive. I concentrate on the contents of the document, the structure of the argument and the cleanliness of both the content and the presentation. That is the extent of my effort at persuasion through presentation.
This is a nice way of saying that I don’t concentrate on the presentation as much as I should. I try to persuade with my content rather than the presentation of said content. I don’t know whether that is the best solution but that is what I find myself doing. Most of my writing is for myself. I am persuaded, that is why it came out the way it did. Persuading other people? I am not so sure.
Takeaway
I am sure that the process is important. Separate the functions of writing, editing, and formatting into discrete tasks, because they are. Vomit it all out on the page, then edit and format the content to ensure that you are presenting well thought-out, reasoned arguments. That is the key to persuasive writing.
By pure coincidence, it's six years ago
tomorrow that I
finally, after years of running Emacs with a bright
white background, moved to using a dark theme. It took a little bit of
getting used to but eventually I got very comfortable with it, and since
then have run everything I can in a dark mode too.
On occasion, in the last year or so, I've had this urge to move to something
darker. Also, in part, it's an urge to change things up a little. I felt it
was time for a refresh of how my Emacs looks. I've tried a few themes, but
none have ever stuck. When trying them I've run into various issues:
It just didn't look nice at all
Too many other things I use in Emacs didn't get themed
It looked like there was going to be too much work to do to really theme
things well
However, yesterday evening, after making an effort to simplify my mode
line, I was determined to find a
darker theme that I would be happy with. I think I finally managed!
I've settled on modus-vivendi from modus
themes. Out of the box it felt
right, and from what I can see in the documentation there's an amazing
amount of customisation you can do. The key point there too is the
documentation; there's so much of it, it's incredibly comprehensive.
For example: the default choice for the mode line is to have an unsubtle
border around it -- presumably to create a good contrast. I found that far
too distracting and was wondering what I could do about it. I didn't have to
wonder long, the documentation addresses exactly that
situation.
Another downside I ran into is that the colours that were showing in the
mode line, when I switched to mood-line yesterday, were gone. I spent a
short amount of time last night, and a good hour or so this morning, trying
to wrangle mood-line into something I liked, but I just couldn't get
anything sensible going. Eventually I cracked, fired up
Antigravity, prompted it with:
I am using mood-line for my mode line -- see
init.d/packages.d/melpa/mood-line.el and
https://github.com/emacsmirror/mood-line
I am using https://protesilaos.com/emacs/modus-themes as my theme
I would like to have finer control over the parts of the mode line I've
configured. For example, I'd like the buffer name to stand out in an
informative colour, but one that is part of the modus theme's colour
scheme.
Don't make changes yet, but help me understand how I should do this in a
maintainable way.
and then spent about 20 minutes going back and forth, refining what I
wanted; this got me a
result
I'm happy with from a visual point of view. I still need to fully review the
code and the approach it took, but it isn't too far removed from what I'd
been trying myself.
Overall I'm pleased with the result, and this is the longest I've stuck with
a new theme (at this point I'm probably about 4 or 5 hours into working in
it). I think that says something significant. I can see myself still wanting
to tweak some aspects of it though. For example, the left-hand fringe
doesn't feel quite right, in a way I can't quite put my finger on. While I
want it to stand out from the main editing area, it feels... disconnected in
some way. Also the background colour of the mode line still feels like it
doesn't quite blend how I'd like.
Now to see if this lasts...
Seriously, just the once, but that happened. I took that as a sign
from the Lisp gods that I was doing something sinful. ↩
When we call dired from Lisp, we can pass it a list of files instead
of a directory. This gives us a fully fledged Dired buffer for those
files. My most common use-case is to produce flat listing, so that I
do not have to go searching in exactly which directory some file is
(e.g. in the Downloads folder there is some zip archive that I
downloaded with a bunch of files in a complex structure).
A flat Dired listing
For a while now I have been using my own command to create a Dired
buffer from the current directory (which can always be updated on
demand with M-x cd). It is prot-dired-search-flat-list. Here is
the code:
(defvarprot-dired-regexp-historynil"Minibuffer history of `prot-dired-regexp-prompt'.")(defunprot-dired-regexp-prompt()(let((default(carprot-dired-regexp-history)))(read-regexp(format-prompt"Files matching REGEXP"default)default'prot-dired-regexp-history)))(defunprot-dired--get-files(regexp)"Return files matching REGEXP, recursively from `default-directory'."(directory-files-recursivelydefault-directoryregexpnil));;;###autoload(defunprot-dired-search-flat-list(regexp)"Return a Dired buffer for files matching REGEXP.
Perform the search recursively from the current directory."(interactive(list(prot-dired-regexp-prompt)))(if-let*((files(prot-dired--get-filesregexp))(relative-paths(mapcar#'file-relative-namefiles)))(dired(cons(format"prot-flat-dired for `%s'"regexp)relative-paths))(error"No files matching `%s'"regexp)))
I could modify prot-dired-search-flat-list to also prompt for a
directory, though I optimise for the common workflow of operating from
where I am (and I generally do not like overloading the C-u with
special cases that I will never remember—a new command with a name I
can search for is better).
Flat listing limited to last modified since DAYS
Yesterday I had the need to browse a massive directory, but only
wanted to get a couple of files out of it. I realised that I had to
filter my last modified, so I extended my above use-case with the new
command prot-dired-search-flat-list-since-days. Here is what I came
up with:
(defvarprot-dired-days-prompt-historynil"Minibuffer history for `prot-dired-days-prompt'.")(defunprot-dired-days-prompt()"Prompt for days and return them as a number."(let*((first(carprot-dired-days-prompt-history))(default(when(stringpfirst)(string-to-numberfirst))))(read-number"Number of days: "default'prot-dired-days-prompt-history)))(defunprot-dired--get-last-modified(filesdays)"Return list of FILES last modified since DAYS."(seq-filter(lambda(file)(and-let*((attributes(file-attributesfile))(last-modified(nth5attributes))(last-modified-seconds(time-to-secondslast-modified))(current-time(current-time))(current-time-seconds(time-to-secondscurrent-time))(delta-seconds(*days246060))(oldest-seconds(-current-time-secondsdelta-seconds))(_(>=last-modified-secondsoldest-seconds)))))files));;;###autoload(defunprot-dired-search-flat-list-since-days(regexpdays)"Return Dired buffer with files matching REGEXP up to DAYS since last modification.
Perform the search recursively from the current directory."(interactive(list(prot-dired-regexp-prompt)(prot-dired-days-prompt)))(if-let*((files(prot-dired--get-filesregexp)))(if-let*((files-filtered(prot-dired--get-last-modifiedfilesdays))(relative-paths(mapcar#'file-relative-namefiles-filtered)))(dired(cons(format"prot-flat-dired since %d days for `%s'"daysregexp)relative-paths))(error"No files last modified within the last %d days"days))(error"No files matching `%s'"regexp)))
Note that I always design my minibuffer prompts to have their own
history, because then I only get relevant entries when I press M-p
(previous-history-element) and M-n (next-history-element) at the
prompt (and the built-in savehist-mode takes care to persist those).
Everything is part of my Emacs configuration: https://protesilaos.com/emacs/dotemacs.
I will not be updating this article, so make sure to check for any
further refinements there.
Every so often I get the urge to change how Emacs looks. Ever since I
finally fell to the dark
side, my Emacs
has stayed looking pretty much the same. I like how it looks, but I do keep
having this urge to find a darker theme, and to also make things just a wee
bit more minimal.
At one point I was very much about, and in favour of, having as much
information as possible in the mode
line.
Eventually I realised I didn't use that much and tried to declutter
somewhat, mostly cleaning up minor mode information with
diminish.
Even then though, I had this feeling that there was still more information
in the mode line than I really needed.
So, just now, as an experiment, I've decided to start fairly clean. I've
dropped powerline and instead
decided to have a play with
mood-line. Rather than use one
of its pre-configured formats, I've had a go at rolling my own:
For any given buffer the mode line display is now:
The status of the buffer
The name of the buffer
The major mode of the buffer
The git status for what I'm working on
The cursor position
Honestly, I'm struggling to think of anything else I really need to see.
Sure, I can imagine there's the odd minor mode I might need to know about,
but generally I either have them enabled all the time anyway, or it's
something so obvious that I know when it's not enabled.
I'm going to run with this for a while now and see how I feel. I can sense
that I might want to tweak a couple of things (at the moment the left-hand
side will move when I change the unsaved status of the buffer; on the right
there's nothing that tells me that this file I'm editing right now is new to
the repo and not part of it yet), but this basic configuration feels clean
and right.
Meanwhile... the search for a theme that is
darker and I actually prefer over the sanityinc-tomorrow
themes
continues. I fear this is going to be a lot harder.
Bozhidar Batsov has a post announcing a couple of new Emacs modes for AsciiDoc. In the usual Batsov way, he’s significantly improved the support for AsciiDoc in Emacs. He loves AsciiDoc but found it hard to use in Emacs because the support was so bad.
I’ve never used AsciiDoc so I don’t know why Batsov prefers it to Org mode. Org mode can be and has been used to produce first class technical documentation. If needed, it can bring to bear all the power of LaTeX to produce a polished product.
As far as I can see, the only reason not to use Org mode is because you’re not an Emacs user or are collaborating on a document with someone who isn’t. It offers everything you’re apt to need short of bringing in a heavyweight dedicated document preparation system. I’m sure Irreal readers not as ignorant as I about the situation can tell us why we should prefer AsciiDoc. Our lines are open.
If you are an AsciiDoc user, Batsov’s two new modes are sure to be a blessing. The update to adoc-mode is designed to work with all versions of Emacs and updates the regex-based font-locking to the current AsciiDoc grammar. It’s perfect for an AsciiDoc user who’s running an older version of Emacs. Asciidoc-mode is the more modern solution using tree-sitter to handle things like font-locking but it only runs on Emacs 30.1+.
Take a look at Batsov’s post for the details on the two modes. And if you know why an Org mode user should care, leave a comment.
Another quick update to
blogmore.el, again to fix an issue
I've run into with the new frontmatter-handling code. This time it's to
address an actual crash that could happen if a property was available but
empty. For example, if a post had frontmatter that looked like this:
And I then went to use blogmore-add-tag, I'd get a crash saying:
Wrong type argument: sequencep, :null
The reason being that tags was being parsed with a value of :null,
rather than (as before) having a value of nil (which of course meant I had
a nice empty list to do things with). It was an easy enough fix.
At this point I think I've managed to shake out any serious issues with the
proper YAML-parsing approach to frontmatter, as I've used it to write a
handful of posts now.
A quick little update to
blogmore.el to fix a couple of
issues introduced by the new YAML-parsing approach to reading frontmatter;
both pretty much stemming from how falsy values are handled.
Simply put, both boolean false values, and also empty values (something
that could commonly happen with tags and series) would end up showing up
in the frontmatter as null. This release handles that situation.
Also, under the hood, I cleaned up some repeated boilerplate related to how
the cached dump calls to BlogMore took place.
The code for categories, tags and series data was almost exactly the same,
save for the actual name of the thing being dumped. So I turned it all into
a macro:
(defmacroblogmore--cache-dump(dump-name)"Generate a function to get DUMP-NAME from BlogMore, with caching."(let((cache-name(intern(format"blogmore--current-%s-cache"dump-name)))(getter-name(intern(format"blogmore--current-%s"dump-name))))`(progn(defvar,cache-namenil,(format"Cache for the list of %s from existing posts."dump-name))(defun,getter-name(),(format"Get a list of %s from existing posts."dump-name)(or,cache-name(setq,cache-name(blogmore--list-of,(symbol-namedump-name))))))))
and now the defvar that creates the variable that holds the cache, and the
defun that creates the getter function for the data, are reduced to this
for all three collections of values:
Sure, I probably could have done all of this in a single global, a central
getter function, and a hash
table,
but the macro approach feels so much more elegant, and more... lispy.
And it’s understandable — things are getting worse and worse all the time, and anybody who is running a web site (that has interesting information) is under constant attack from badly programmed AI scrapers.
But where does that leave us li’l smol peeps who are just scrapin’ a li’l data for ourselves so that we don’t have to type as much?
I’ve got two small use cases that have been torpedoed by this arms race lately — I use the imdb search to find the data on movies I’ve ripped from blu rays that I’ve bought. And I use the Goodreads search when I’m entering (manually) e-books that I’ve bought into the Emacs package for that. (Physical books have ISBNs printed in bar code form, so I can use various APIs for that and don’t need to resort to anything as tawdry as web scraping.)
These are just minor convenience things I’ve gotten used to over the years, so I could give them up… or I could go raging, raging against the dying of the open web.
First try to fetch the URL using the normal, fast method.
If this fails, use Selenium headless. This involves spinning up a web browser and then dumping the resulting DOM.
If this fails, spin up Selenium and a web browser window. This will allow the user to click around a bit, answering any challenges.
In 2) and 3), fetch-dom will save and reuse cookies, so that
hopefully 3) doesn’t happen as much, and 1) and 2) will be successful
more often.
So this requires a Python/Selenium installation that works, and
Chromium installed.
fetch-dom is synchronous by default, but is asynchronous if you give it the :callback keyword parameter.
This seems to work for my use cases — things usually work automatically, but once in a while it pops up a browser window, and I click a bit, and then things work headlessly for a while again.
I was asked recently, "Do you use Org Mode protocol ... for browser
to Emacs interaction? If so, were there any complications to set it up
on Windows? Is there like bookmarklets for capturing or doing
things?"1
At the time I wasn't doing anything too fancy to incorporate Web
Content into Org. I'd copy the URL from Vivaldi's address bar to the
clipboard and (if applicable) the Web Content I'm interested
in.2 Then
in Org, I'd yank the Web Content (if applicable), mark it and then do
org-insert-link (C-c C-l) to turn it into a hyperlink. The marked
text becomes what you see in the document. But I usually just specify
the link Description simply as "LINK." In fact I created a macro
(bound to the Insert key) to do this.
But I've started to use eww as my web browser for this. If I write
something that I need to verify, I'll mark it and invoke
eww-search-words (M-s M-w), which brings me to a DuckDuckGo page of
search results. If I follow a search result that I like, I'll mark a
small section and invoke org-store-link (C-c l) and create the link
with org-insert-link, with the marked content as the Description.
Thus org-store-link captures both the location and the context in one
magical swoop. Here's an animated GIF that illustrates the process.
Note that the video shows me capturing and referring to part of Sacha
Chua's website that shows some neat solutions to launching a web
browser from Emacs.3
If you follow writers at all, you’ll have noticed that many prefer to write their prose in long hand even if they began their writing career with a computer. Tess Gerretsen and Neal Stephenson are two examples that come to mind. Both are serious, established writers who have no need for performative resistance to computers. Indeed, they both use computers to produce the final manuscript. They say they write in longhand to slow things down or to avoid premature editing.
I understand their urge but could never work that way. Writing by hand is excruciatingly slow and even painful to me. I didn’t start writing a lot until I got a computer and could do it without so much effort and discomfort. A middle ground is what’s often called a “writerdeck”. The idea is that it’s a device that’s completely dedicated to writing and is as simple as possible.
Chris Maiorana wrote an article that argued a pad and pen is the ultimate writedeck. I reject that for the reasons I stated above. Maiorana recognizes that often a computer is a good idea and has an article that describes building his own writerdeck. He wanted something free or cheap so he used a Raspberry Pi 4 that he had lying around, put Linux and Emacs on it, and restricted it to text mode. Later he added a few utilities such as Git but it remains a text only machine dedicated to writing with Emacs. Maiorana considers it the “maximum digital minimalism” but I’m more inclined to think of it as a minimal acceptable writing environment.
I don’t do social media other than Irreal, if you consider that social media, so I have no difficulty concentrating on my writing while using my everyday laptop. Not everybody is like that, of course, so if you find it’s hard to resist doom scrolling while you’re supposed to be writing, you may want to take a look at Maiorana’s post on his writerdeck.
"...how can people keep up with what you're learning?"1
I've always kept a low profile on the Internet. It can be a
scary place! But I've been asked to show glimpses of my online
work to the people I was meeting in real life.
I agreed to chat with Sacha Chua about Emacs and Life
(but not the Universe -- that'll be next time). Emacs is worth
revealing oneself for. If people really do want to keep up
with what I'm learning, they can visit here.
My init file2 shows only a small aspect of how I have Emacs
configured. You'll want to see an example of my org file(s),
my diary file, and the Lisp I have tucked away under my home
directory.
Aside from Emacs, my workflow relies on Vivaldi and LibreOffice, so
I'll try to show what I'm doing with them, as well. Perhaps I
can provide screen recordings, too!
"Sometimes it just takes somebody saying, your stuff is
interesting. I'm telling you, your stuff is interesting."3
Rendering an Emacs status bar as an SVG image, like with my svg-line package (demo), really is several times heavier than the native text engine. The skeptics were right. But it doesn't matter in practice: even a fully-repainted 3000-pixel ultrawide bar holds ~77 fps, and a thin inline animation rasterizing a fresh frame every tick runs at 130–520 fps. To put that into perspective, this is still well above the high frame rates that even applications like video games target. More than enough for a text editor if you ask me!
I got two real take-aways from this benchmark. First, the rendering cost of SVG scales with the SVG's pixel area, not with what's drawn on it (text and icons cost the same as you'll see). Second, in any real Emacs config the bottleneck is the content query (I'm looking at you, git), not the renderer (I'm looking at you, SVG, with doe eyes).
2. Clarifications Before we Dive In
I'm not saying that SVG should be the basis of a game engine in Emacs. I am saying that Emacs has more than enough headroom over the frame rates that games target. 24fps is considered the minimum for a perceivable animation (30fps for a smooth one, 60fps for a good one), and competetive gamers target fps in the 200s. As you will see from the data, Emacs meets these thresholds and then some.
I'm also not saying that Emacs's SVG frame rates hold linear time complexity O(1) across all pixel scales. In fact, the benchmark demonstrates the opposite (SVG rendering fps decreases as pixel scale increases). I am saying that Emacs SVG rendering is more than performant enough for its common use cases, like rendering responsive status bars.
3. Why Benchmark This?
The skepticism is reasonable. Emacs is optimized for a small number of cached images, while a status bar that changes on every redisplay can generate a new image many, many times per second. Intuitively, that should be slow.
But other Emacs SVG projects show smooth 60 fps animation, as one redditor pointed out, and anecdotally svg-line felt fast on my end.
I felt compelled to measure it, so I did, with a self-contained harness (to borrow the redditor's term) that runs in bare emacs -Q.
4. Results: SVG vs Native Text Engine
You can run the benchmark yourself, in a bare emacs -Q or your own Emacsen. My setup is Emacs 31.0.50 (native-compiled), librsvg (linked into my build), on a 2025 M5 Mac running Tahoe 26.1.
Three renderers draw the same thing at three widths (a narrow split, a normal window, and an ultrawide monitor): an SVG bar of text, an SVG bar of Nerd-Font icon glyphs, and (as the baseline) the native text engine drawing the same characters.
4.1. SVG Rendering Text
SVG / text
mean ms
min ms
max ms
mean fps
min fps
narrow 800px, 65c
3.44
3.09
3.96
290
253
medium 1800px,149c
7.49
6.98
7.91
134
126
large 3000px,249c
12.91
12.39
13.37
77
75
4.2. SVG Rendering Icons
SVG / icons
mean ms
min ms
max ms
mean fps
min fps
narrow 800px, 65c
3.60
3.37
3.80
278
263
medium 1800px,149c
7.85
7.47
8.53
127
117
large 3000px,249c
13.31
12.67
14.10
75
71
4.3. Built-in Rendering Text
BUILT-IN / text
mean ms
min ms
max ms
mean fps
min fps
narrow 800px, 65c
0.16
0.13
0.23
6377
4378
medium 1800px,149c
0.21
0.19
0.37
4789
2686
large 3000px,249c
0.26
0.24
0.33
3842
3046
4.4. Analysis
SVGs perform at all widths. Even the large 3000-pixel bar (an ultrawide-monitor width), repainted every frame, stays above 60 fps: ~77 fps for text and ~75 fps for icons, and the worst trial across the run is still 71 fps.
Text and icons cost essentially the same (290 vs 278, 134 vs 127, 77 vs 75). The cost is dominated by rasterizing the SVG as a whole, so what is painted on it doesn't seem to matter. The relevant correlate is the SVG's pixel area.
The native engine is ~20–50× faster. The skeptics are right that SVG is heavier because a monolithic image is re-rasterized in full whenever any pixel changes, while the text engine updates incrementally from cached glyphs, and the gap widens with width for that reason. But!!! This doesn't matter in practice. Even in the worst case, SVG never drops below the gaming gold standard, which is more than enough for a text editor.
5. A Live Inline Animation
Why talk frame rates without an animation? Here, three purple icons (Emacs, Org, Image) glide back and forth along a thin white bar, measured across three widths.
line animation
mean ms
min ms
max ms
mean fps
min fps
small 300x56px
1.94
1.77
2.26
517
443
medium 700x56px
4.03
3.75
4.55
248
220
large 1400x56px
7.45
7.04
7.77
134
129
An inline animation rasterizing a fresh SVG every frame runs at 130–520 fps, and the worst trial is still ~129 fps.
NOTE: My screen recording can't convey the real frame rate because my screen-capture tool is capped at 60 fps.
Run the demo yourself (below) to see the true smoothness.
6. How I Measured It
The harness renders a status-bar-shaped image (or, for the baseline, native text) into a buffer, re-renders it every frame, forces a redisplay, and times the wall-clock per frame in milliseconds (which the tables also report as fps).
(defunsvg-bench--time(render-fn reps)"Render REPS frames, forcing redisplay, and return ms per frame."(let((gc-cons-threshold most-positive-fixnum))(clear-image-cache)(funcall render-fn 0)(redisplay t); warm-up, untimed
(let((t0 (float-time)))(dotimes(i reps)(funcall render-fn (1+ i))(redisplay t))(/ (* 1e3 (- (float-time) t0)) reps))))
Some details on what makes this demo reflect practical use of SVG in Emacs:
I ran it in a real GUI frame. If you ran this with --batch or emacs -nw there's no display and rasterization is skipped.
I set gc-cons-threshold during timing and I discard a warm-up frame (because the first render loads librsvg).
I force a miss in Emacs's image cache. Emacs caches each rasterized image by its full data string, so if a frame's string repeats, the cache serves the bitmap and the benchmark measures a cache hit rather than a real render. Rotating through a small pool of content (say ten icons, or a short alphabet) repeats every few frames. So each frame in my benchmark carries a 2px per-frame colour marker (a tiny non-text rectangle) that makes the whole-image data string unique and guarantees a genuine re-rasterization.
7. In Practice, the Bottleneck Is Not the SVG
The benchmarks above use synthetic content precisely so they measure the rendering, not the performance of any indicator you might put in a status bar.
In a real configuration, a single synchronous git query in the version-control segment runs ~7.6 ms, which is on the order of painting the entire SVG bar, and far more than rendering the one segment it occupies. A native mode line showing the same version-control state would pay this cost too.
When an Emacs status bar feels slow, an I/O-bound content function is almost certainly the reason.
8. Conclusion
SVG status bars are several times more expensive than the native text engine — and also far faster than 60 fps, even at ultrawide widths. The native engine keeps an order of magnitude in reserve, but SVG has plenty for the job, and in practice the slow part of a status bar is the content it queries, not the engine that paints it.
9. Run it on Your End
The harness is one self-contained file, svg-bench.el, in my Emacs configuration repository (built-in svg and cl-lib only). In a graphical Emacs:
emacs -Q svg-bench/svg-bench.el
Then M-x eval-buffer, and run any of the demos — svg-perf-text, svg-perf-icons, builtin-perf-text, svg-perf-animation. The full report comes from svg-perf-benchmark (the three status-bar tables) and svg-perf-animation-benchmark (the animation table).
Regular readers know I have a soft spot for
AsciiDoc – I’ve written about it more than once, and
it’s the markup behind the documentation of most of my bigger OSS projects
(CIDER, nREPL, Projectile, RuboCop). It hits a sweet spot Markdown never quite
reaches: rich enough for proper technical writing (admonitions, includes, real
tables, cross-references), without dragging in the full ceremony of something
like DocBook.
There was just one problem, and it nagged at me for years: editing AsciiDoc in
Emacs was never much fun.
Background
For years the only real option was adoc-mode, and it was showing its age. The
font-locking was uneven, it predated modern Asciidoctor syntax, and it lagged
far behind what markdown-mode (and org-mode) offered. So I’d catch myself
reaching for Markdown in situations where AsciiDoc was clearly the better
tool – not because Markdown was better, but because markdown-mode was. That
always bugged me.
Eventually the itch got bad enough that I did something about it. Back in 2023 I
took over maintenance of adoc-mode,
which had been dormant for years, and set myself a clear goal: get it to feature
parity with markdown-mode. More recently I also started a brand-new
asciidoc-mode built on top of
tree-sitter. The target for both is the same – AsciiDoc support in Emacs that’s
on par with Markdown, and ideally not far off from Org.
Less is more, unless it’s modes
Why two modes? They scratch slightly different itches:
adoc-mode is the classic, regexp-based mode. It works on any reasonably
modern Emacs, has no external dependencies, and now ships a pile of
interactive features (markup commands, list editing, image preview, tempo
templates).
asciidoc-mode is the newer, tree-sitter-based mode. It leans on a real
grammar for robust, accurate highlighting and good performance in large
documents. It’s leaner by design, and it needs Emacs 30.1+ with tree-sitter.1
If you want the kitchen sink on any Emacs, reach for adoc-mode. If you’re on a
recent Emacs and want highlighting backed by an actual parser, try
asciidoc-mode. Pick whichever fits your setup – both are actively maintained.
Recent developments
I’ve spent a good chunk of the past month bringing both modes to a place I’m
genuinely happy with, and they’re now mostly feature-complete as far as I’m
concerned. Some highlights:
Modern AsciiDoc, not legacy AsciiDoc.py. Both modes now track the modern
Asciidoctor spec – something I’d
wanted to do for a while.
+text+ and ++text++ are treated as passthroughs rather
than monospace, curved-quote syntax ("`text`") is recognized, the block
ID shorthand [#id] is supported, checklists are highlighted, and the menus
and templates dropped a bunch of deprecated AsciiDoc.py leftovers.
More uniform font-locking. I went through the faces in both modes and
aligned them with markdown-mode and org-mode: bold renders as plain bold,
emphasis as plain italic, structural markup (delimiters, list markers) fades
into the background, and dedicated semantic faces cover metadata, URLs,
footnotes, highlights, and roles. Switching between Markdown and AsciiDoc no
longer feels jarring.
Navigation that actually works. Clickable cross-references and links, an
xref backend over anchors, context-aware completion, and – for adoc-mode
– cross-file Antora cross-reference resolution.
Tooling integration. Asciidoctor-backed preview/export and a Flymake
checker that reports parser errors inline.
Native code-block fontification.[source,LANG] blocks in asciidoc-mode
are highlighted using the language’s own major mode, just like in
markdown-mode and org-mode. adoc-mode had added support for this a while
back.
Getting asciidoc-mode where I wanted it also meant sending a few fixes
upstream to the
tree-sitter-asciidoc
grammar it builds on. A grammar-backed mode is only as good as its grammar, so
some of the work happened a layer below Emacs. If you’re curious about that side
of things, I wrote up the broader experience in
building Emacs major modes with Tree-sitter.
Give it a try
If you’ve been avoiding AsciiDoc in Emacs because the tooling wasn’t there – I
get it, that was me too. But the situation is genuinely different now. Grab
adoc-mode or
asciidoc-mode, point it at one of
your .adoc files, and see how it feels.
And please share your feedback. Both projects are at the stage where real-world
usage surfaces the rough edges I can’t see myself. Bug reports, ideas, and PRs
are all very welcome on the respective issue trackers.
Together we can make AsciiDoc a first-class citizen of the Emacs ecosystem!2
That’s all from me, folks! Keep hacking!
Also, I really wanted to name something asciidoc-mode. ↩︎
Afterwards we’ll aim for world domination, of course. ↩︎
I'm still chipping away at the backlog that built up while I was away, but if there's anything in particular you'd like me to look at, feel free to ping.
Luckily, agent-shell is built on ACP, which sidesteps the problem. When a vendor changes course, you can swap providers and keep using your preferred tool. No need to reshape that hard-earned muscle memory.
On that note, the list of agents supported by agent-shell continues to grow.
Supported agents
Here's a list of the latest agents now supported by agent-shell.
Speaking of vendor-neutral tools being more important than ever, there are a couple of ways to help keep agent-shell going. Some cost money, others just a click. All are appreciated ;)
Sponsorships for agent-shell longevity
agent-shell has been attracting quite a few users. It's nice to hear folks are using agent-shell on a daily basis. They are often relieved agent-shell exists as an alternative to AI-tools commonly mandated at work. Those tools have well-funded engineering teams behind them, while agent-shell is just me, an indie dev ;) Time spent on agent-shell is time away from work that pays the bills, so if it's useful to you, please consider sponsoring the project.
Every individual sponsorship genuinely helps keep the project going. And if your employer benefits from your agent-shell use, they're typically in a position to contribute at a scale individuals can't, so nudge them to chip in too.
Hey, I'm looking at you, folks at Google, GitHub, GitLab, NVIDIA, Oracle, Red Hat, Yelp, Venmo, ARM, Spotify, Augment Code, Hinge, Mercury, Nubank, Veeva… Some of you are using agent-shell. Nudge your employer ;)
Speaking of GitHub stars, agent-shell is now my most popular Emacs package, recently overtaking chatgpt-shell.
New markdown renderer
agent-shell now ships with a brand new, more performant inline markdown renderer. This is the biggest internal change in some time. Enabled by default via agent-shell-markdown-render-function (moving away from the overlay-based renderer in shell-maker).
Access/navigate table content
Table content is now accessible. Point can land on any cell, which wasn't possible with the previous overlay implementation. In addition, tables are now also navigable: TAB and S-TAB move between cells.
Improved source block support (enabled by default)
Source-block syntax highlighting is now on by default. The per-snippet copy button is now keyboard-accessible too (previously mouse-click only, due to the overlay implementation).
New blockquotes support
Blockquotes now render in both shell and viewport. More importantly, you can select text in either a viewport page (or the shell itself), press r (for reply) and the selection becomes a blockquote in a fresh prompt.
Viewport
Shell
Session restoration
Session restoration got a meaningful overhaul (#605 by @nhojb), now exposed via agent-shell-session-restore-verbosity, with four levels:
minimal (default): title only, so restore is fast and quiet (needs session/resume support).
last: render the last prompt turn (needs session/load support).
first-last: render the first and last prompt turns (needs session/load support).
full: replay the whole conversation (needs session/load support).
Feature availability is agent-specific, requiring either session/resume or session/load request support. agent-shell degrades as needed, ultimately falling back to creating a new session.
Relatedly, agent-shell-session-strategy now defaults to 'prompt, and 'new-deferred has been retired.
Session forking
You can now fork the current session, starting a new shell that shares the conversation history so far and diverges from there. Invoke via M-x agent-shell-fork.
Restart/reload session
You can now restart the current shell anew (drop history) via M-x agent-shell-restart or reload (keep history) via agent-shell-reload.
Downloads/Temp shells
The new agent-shell-new-downloads-shell and agent-shell-new-temp-shell commands create agents anchored at either ~/Downloads or a temp directory. Both are also reachable via C-u M-x agent-shell.
TRAMP support
acp.el #20 by @martenlienen landed support for ACP connections over TRAMP, now making it possible to drive remote agents from agent-shell. Pair it with agent-shell-tramp for the user-facing integration.
Viewport improvements
Viewport interaction (setq agent-shell-prefer-viewport-interaction t) continues to be my primary way to interact with agents. It is focused (see only the latest interaction), fast (single-key bindings: y = yes, c = continue, m = more…), and offers a richer editing experience (dedicated prompt-crafting buffer).
The viewport is just a viewport to shell content. You can have your cake and eat it too, by jumping to the related shell buffer if needed.
Queueing
From a viewport, you can press r to reply to the latest agent response. In the past, you could only reply to idle agents. You can now press r to reply to busy agents too, automatically queuing requests on submission.
List editing mode
A new (basic) agent-shell-list-edit-mode lets you edit list-style content inside the viewport.
Improved buffer selection
Some commands prompt you to pick one of your active shell buffers (e.g. M-x agent-shell-send-region-to). The picker now shows extra context for each buffer to help you choose.
The same mechanism is now used by the new M-x agent-shell-switch-buffer command. More on the underlying API later.
M-x agent-shell-ui-toggle-fragment toggles the fragment at or near point (DWIM).
M-x agent-shell-ui-toggle-all-fragments cycles globally between all-expanded and all-collapsed.
Together they replace the previous agent-shell-ui-toggle-fragment-at-point, which is now an internal primitive.
c joins the viewport reply gang
You can now press c from a viewport to quickly send a "continue" request, joining the rest of the single-key reply shortcuts:
c: replies "continue" (new)
y: replies "yes"
m: replies "more"
a: replies "again"
1 … 9: replies with the corresponding numbered choice
r: opens the reply compose buffer
R: same as r, with the agent response quoted
More compact status rendering
Tool call status is now rendered as a compact icon-based label by default (agent-shell--inverse-icon-status-kind-label). agent-shell-styles.el ships several alternatives, picked via agent-shell-status-kind-label-function.
You can now set a default model and session mode for Codex via agent-shell-openai-default-model-id and agent-shell-openai-default-session-mode-id (#405 by @robjgray). Both must match an ID from Codex's "Available models" / "Available modes" listings.
Emacs 31 fixes
Headers had a few rendering hiccups on Emacs 31. These are now fixed (#588 and #590 by @nhojb, #463 by @ftlio). Warnings from deprecated when-let usage were also cleared.
Wayland clipboard support
wl-paste is now a supported clipboard handler for pasting images on Wayland (#461 by @martenlienen).
Windows clipboard support
Similarly, pasting clipboard images now works on Windows via PowerShell (#572 by @repelliuss).
Header improvements
The graphical header got minor tweaks here and there. For example, thought level is now displayed in the header. It can be changed via M-x agent-shell-viewport-set-session-thought-level as well as menus (#601 by @martenlienen).
Session config options
agent-shell now supports ACP session config options (#553 by @greggroth and #613 by @catern). Bind C-c C-s (or call agent-shell-set-session-config-option) to pick from the options the agent advertises. Broadcasted as config-option-update and available externally via agent-shell-subscribe-to.
Interrupt confirmation
You can now skip interrupt confirmations by unsetting agent-shell-confirm-interrupt (#424 by @emil-e).
Public functions
Resume sessions by ID
You can now resume an existing session by its ID via M-x agent-shell-resume-session (#332). Primarily useful for external integrations.
Outgoing request decorator
You can now use agent-shell-outgoing-request-decorator to tag or transform outgoing requests.
Subscribe to idle events
agent-shell-subscribe-to now broadcasts idle events (#509 by @arthurgleckler).
Getting shell buffers
agent-shell-shell-buffer returns the underlying shell buffer for the current context.
Last vs interaction at point
agent-shell-goto-last-interaction jumps to the latest prompt/response pair, while agent-shell-interaction-at-point returns the interaction at point as data.
Shell status
agent-shell-status returns 'busy, 'blocked, or 'ready status for any shell buffer.
Session title
The agent-supplied session title is now exposed via the session-title-changed event (delivered via agent-shell-subscribe-to) (#559 by @smagnuso). Can be handy for buffer names, bookmarks, or recent listings.
New third-party packages
The agent-shell family of third-party packages keeps growing. Recent additions:
#548: Copied highlighted text from agent output includes trailing backtick
#563: "Cannot modify map in-place" when starting agents
#577: agent-shell-get-config does not work in an agent-shell-command-prefix function
#587: Long region preview's "Expand…" button is sent literally to the agent
#617: OpenCode: consent prompt shows empty input when request_permission arrives before tool_call_update populates rawInput
Lots of polish
Beyond what's showcased, I've poured much love and effort into polishing the agent-shell experience. Interested in the nitty-gritty? Have a look through my regular commits.
Make the work sustainable
If agent-shell is useful to you, please consider sponsoring the project. I'm now back to working on agent-shell daily.
LLM tokens aren't free, and neither is the time dedicated to building this stuff (especially as an indie dev). I also have bills to pay ;)
Unless I can make this work sustainable, I will have to shift my focus to work on something else that is.
Ian Pan has curated a nice collection of Emacs caught in the wild. By “in the wild” I mean “in popular culture”: things like movies and comics. Most of us have seen the familiar scene from Tron but Pan has a bunch of others.
One example is the famous scene from Silicon Valley in which Richie and Winnie start arguing about Tabs versus Spaces and end up discovering that one is a Vim user and the other an Emacs user. I’ve seen that scene many times but didn’t realize where it came from so I learned something new from his post.
The other surprising thing—to me—is that Emacs also makes appearances in comics. What’s interesting is that you rarely see any editor other than Emacs or Vi(m) mentioned outside geek circles. Perhaps the current cohort of hackers will change that and we’ll start seeing references to VS Code. Or maybe not. VS Code does have a lot of users but I haven’t seen the same culture grow up around it. We’ll see.
However, as a digital minimalist, and one who writes at a high enough volume, a writerdeck starts to make a lot of sense. So I thought I’d try to make one.
But, I wanted it to be a “low buy” or “no buy” situation. Luckily, I had a Raspberry Pi 4 lying around unused, so I snapped it up. I installed a lightweight, minimalist distribution of Debian called DietPi and installed Emacs with no GUI. (Of course, I also installed git and a lot of other stuff by now, but I am keeping it GUI-free.)
We’re talking MAXIMUM digital minimalism here.
I am using tmux as a sort of window manager, spawning sessions and windows and switching between them as needed. I’ve also opted to run Emacs as a daemon and connect to it with emacsclient, so no matter what session or window I’m in, I’m attached to the same running Emacs state. This means I can view any and all available buffers and have Claude edit Emacs lisp files and see live results without having to reload Emacs.
For aesthetic reasons, I’ve opted for an “amber CRT” color scheme with the available 16-color palette in the text interface. This makes my workstation feel like a DOS-era word processor.
I love this so much it’s hard to contain my excitement.
I plan on making a more in-depth video on this topic later to actually demonstrate the system live and show some of the config-mongering I went through to get it just right.
I’ve really enjoyed the results as I’ve grown accustomed to a purely text-based (no mouse!) workflow. The only downside is that it reverses the classic Emacs paradigm of having Emacs colonize my desktop. Instead, Emacs is a guest in tmux. C’est la vie.
When I released blogmore.el v4.7.0
yesterday I finished off by saying that it was my intention, at some point,
to rework the frontmatter-handling code so that it did proper YAML parsing.
As often happens with these sorts of things, "some point" ended up being
that evening.
I've rewritten everything to do with handling properties in the frontmatter
so that it now uses yaml.el. This has a
number of knock-on effects. The first and most obvious effect is that
anything that is a list/array in the frontmatter is actually properly
treated as a list. A good example here is tags. Now you can have your tags
look like:
and blogmore.el will still handle things fine. The same holds for series
too.
It should be noted, however, that because I'm now using actual YAML
serialisation code, most other forms of a list will all end up being
transformed into this kind:
and you make an edit to the tags via blogmore.el, it will end up as the
version enclosed in []. BlogMore itself
supports all three versions so this works fine.
There is a breaking change here too, which in part explains the reason I
bumped the version to 5.0.0: because series can now be treated as a list
I've removed the blogmore-set-series command and instead replaced it with
blogmore-add-series and blogmore-remove-series. Both can of course be
found in the transient menu.
Another big change in this release is the way that existing values are
loaded up from your blog. Previously, when you went to add a category, tag
or series, blogmore.el would use
ripgrep (or a combination of find
and grep if rg wasn't available) to pull out values to help populate a
completion list. This worked fine as long as a) the frontmatter property was
all on one line and b) the body of a post didn't contain something that
looked like a frontmatter property. With this release of blogmore.el I've
dropped this approach in favour of calling blogmore itself and using the
dump command to get
the actual lists of categories, tags and series.
This does mean that BlogMore needs to be installed in a location where
blogmore.el can see it, and to help with this I've added a new defcustom
called blogmore-command. By default this is set to call whatever version
of blogmore can be found in your exec-path; if this results in
unexpected behaviour you can set blogmore-command to point to a specific
copy of blogmore.
There is, however, a small downside to this beneficial1 approach: calling
on blogmore and parsing all posts to get the values is generally going to
be slower. With this in mind I've built in a cache for these values. The
first time you load up the categories, tags or series, the values are held
on to so that subsequent prompts are instantaneous (meaning there is no
further call to blogmore). To ensure this doesn't confuse things, when you
switch blog (blogmore-work-on) the caches are cleared. In the unlikely
event that there is a problem with this approach, I've also added a
blogmore-clear-caches command to force the clearing of the caches.
There are some other small QoL changes under the hood and also to the
interface. I've moved some things around in the transient menu, and also
ensured that a couple of options are better-disabled depending on the
context.
All of this makes the package even more robust. Something that started as a
quick hack back in March has turned
into a tool I heavily lean on. Hopefully, for anyone who might happen to use
BlogMore and GNU Emacs, it'll be a useful daily-driver for them too.
The benefits being: only values in frontmatter appear, inconsistent
casing is cleaned up, etc. ↩
My ongoing journey with vc-dir and vc-mode led me into wanting to delete a stash (not to pop). There are "z" keybindings in vc-dir:
z c vc-git-stash
z p vc-git-stash-pop
z s vc-git-stash-snapshot
but what about delete?, and are there any others?
In vc-dir you get a rather nice little Stash section tacked on at the bottom listing all your stashes:
I genuinely assumed I was missing something obvious, so I did the sensible Emacs thing and hit C-h m to describe the mode, scrolled through the whole keymap, and, nothing about stashes at all.
Well how about C-h b (describe-bindings)?, initially nothing!, however I stumbled on a solution, if the point is on a stash name, the following is exposed!
C-k vc-git-stash-delete-at-point
RET vc-git-stash-show-at-point
= vc-git-stash-show-at-point
A vc-git-stash-apply-at-point
C vc-git-stash
P vc-git-stash-pop-at-point
S vc-git-stash-snapshot
Surprisingly difficult to find.
and C-k does obviously seem a natural fit to delete a stash, but what wasn't obvious was the fact that the point had to be on the stash name.
I couldn't quite understand why these keybindings were so difficult to find, so I went digging into vc-git.el and there it was, the bindings are not part of vc-dir-mode-map at all, they live in their own little keymap:
And the crucial detail, this keymap is not installed as the major mode map, it is slapped directly onto the stash lines as a keymap text property when those lines are rendered. So the bindings are only live when point is literally sitting on a stash, which is rather elegant actually, but it does mean describe-mode never sees them, because C-h m only reports the major mode's own keymap, and a text-property keymap is invisible to it. That explained my confusion completely, I was not going mad after all!
And the Emacs manual, well I did have a little look but found nothing. It seems these keybindings are almost impossible to find, but now I have found them this blog post should help me to remember.
So, lesson learned, and a genuinely useful one I think, C-h m is not the whole story. When a mode renders interactive regions, buttons, clickable lines, embedded widgets, those often carry their own text-property keymaps that describe-mode will never show you, and the move in those situations is C-h k or C-h b with point actually on the thing.
Anyway, C-k on a stash line to drop it, that is the headline, write it on a sticky note, you will want it eventually!, if you are a vc-mode user of course, I suspect that magit has this very discoverable already through the stash menu.
Quick announcement: this blog now lives on the small net too. If you have a
Gemini client around, point it at:
gemini://gemini.rahuljuliato.com
You'll find the same posts there, rendered as plain gemtext.
Wait, Gemini?
Gemini (the protocol, in case the name now
reminds you of other things) is a small internet protocol that sits somewhere
between Gopher and the early web. It works like this: the client sends a single
request, receives a single response, and the connection is done, always over
TLS. Pages are written in a tiny markup format called gemtext, which gives you
headings, links, lists, preformatted blocks, and that's about it. A link is
always its own line, so pages end up reading like a well-organized text file.
The whole spec is short enough to read in an afternoon, and people have written
servers and clients for it in pretty much every language you can think of. The
community around it is usually called the "small net" or "smolnet": personal
capsules (that's what sites are called over there), gemlogs, and a general
feeling of the web before it became an application platform.
I've been lurking in Geminispace for a while and finally decided this blog
should have a capsule of its own. The mirror is generated from the same
Markdown sources as the web version, so both stay in sync.
Browsing it from Emacs
This site has always been totally browsable on EWW, I wanted that by design,
the web version degrades gracefully to plain HTML and reads just fine in a text
buffer. But EWW speaks HTTP only. For Gemini (and Gopher, and Finger), the
package you want is elpher. It's available
on NonGNU ELPA, so a plain M-x package-install RET elpher RET gets you there. Then:
M-x elpher-go RET gemini://gemini.rahuljuliato.com RET
It renders gemtext beautifully in a buffer, history and bookmarks included, and
it integrates gracefully with EWW: bump into an http:// link inside elpher
and it opens in EWW, follow a gemini:// link from EWW and elpher picks it up.
EWW for the big web, elpher for the small one, and you never leave Emacs.
Other clients
The official project site keeps a list of clients for every taste, from TUI
ones like amfora to full GUI browsers like Lagrange:
DC Toedt is a lawyer and professor of practice who uses Emacs and Org Mode. He wanted a small Emacs Lisp function to convert Org Mode syntax to Markdown and copy it to the clipboard to make it easier to copy the materials he's writing for a course on contract drafting. This seems to be a common need, and here are several other approaches:
You can, of course, set a new one too, but the idea here (as with categories
and tags) is that you can quickly find back an existing series and add the
current post to it.
Also, as with tags, the expectation is that either a single series is being
used, or if more than one series is in play for a post they'll be listed as
a comma-separated list. The issue here is that while BlogMore supports this:
series:-Some series of posts-Some other series of posts-Yet another series of posts
the frontmatter-handling code in blogmore.el isn't very sophisticated at
all; it doesn't actually handle it as actual YAML, instead just treating it
as a set of key/value pairs separated by a colon.
At some point soon I want to give blogmore.el a revamp and base all of the
frontmatter-handling code on something like
yaml.el. I did do some experimenting
last night to drop it in and handle proper lists. It worked well enough, but
I abandoned the work as I realised I really wanted to start again from
scratch and build blogmore.el from the bottom up using that package.
Sacha: There's a 10-second delay, so I cannever quite tell when I'm starting to start, butI think I'm going to do that now.Okay, let's go.Okay, I have pressed the Go Live button.Let's see how it goes.So this is Yay Emacs 33 with Prot:Sacha and Prot Talk Emacs.Today, we're going to be talking aboutunderappreciated Emacs built-ins, which is thetheme for this month's Emacs carnival.Sacha: Kind of like this, you know, shared, lots ofpeople writing or talking about a specific topic.This one is hosted by Ross A. Baker.(Thanks for hosting that!)Anyway, so I'm here with Prot. I was verytempted to just dive into this brain dump likelast time about...Let's start with the kinds of problems thatnewcomers and intermediate users might run into,especially the problems they don't even knowabout because Emacs would allow them to do thingsthat other editors might not offer.But they've got to think about it first, right?They've got to discover that this is a need of theirsand that Emacs can help them with it.So maybe this conversation can be a high-leveldiscussion of these concepts to help peopledevelop this intuition for what's out there,particularly for the things that Emacs doesdifferently compared to other editors.And if we start with a problem, and I haveseveral that I often run into in my own life, youmight suggest others as well.Then we can talk about how the things thatare built into Emacs can support that and howthey fit together at a high level. We don'thave to go into "This is precisely howto start a keyboard macro and how to stop it."People can look that up in the manual. But theidea of a keyboard macro and how it's useful,that would probably be a good thing for aconversation.Then for the advanced users who are listeningto this, we can sprinkle in some things we'veseen about some really advanced uses of thesebuilt-ins, because there's a lot of high-leveluse that I haven't even got into yet.So Prot is here, which means that because you'vegot two people, you can see how these same toolscan be used in different ways to supportdifferent workflows.I'm going to suggest some problems that I have.Of course, you can share some from yourexperience and from the times that you've coachedother people.
2:27Focus and distraction
Sacha: My main problem with life in general.is focus and distraction.Because I have a kid, my focus time is veryunpredictable.It can be interrupted any moment by somebodyneeding help.My life over the last 10 years has mostlybeen about five minutes here, 10 minutes there,maybe 15, one hour of focus time if I'm lucky.This is a universal challenge.Well, some people actually get to focus, but mybrain is not one of those focusable things.It has to work in stops and starts.Any chance this is a problem that you also run into?Prot: Not to that extent, but I have thepropensity to go down rabbit holes.I will go really deep, like really deep.You give me something which I know nothing about,I will become an expert in it.But of course, this is a problem when you combineit with curiosity, because now you want to learneverything.Thankfully, I have learned to control myself.If you give me something I don't know about,I will say, OK, sounds very tempting, but I willnot even try.I won't even go down the rabbit hole.Sacha: So these aretwo sides of the same problem,and something that a lot of people will resonatewith... When you're working on something and yourealize, okay, I've got to go do this other thingfirst or, oh, I'm curious about this questionthat has come up in my brain.I want to go down that rabbit hole.How do we manage this?Emacs is here to help.
3:54Org Mode and other note-taking, task-management systems
Sacha: My first recommendation for this problem is:take advantage of Org Mode or otherbuilt-in note-taking task management supportsystems because it...Sometimes people think, okay, an IDE is just anIDE, right?If they're programmers, it's just for code.Sometimes people are writing. They're usinga text editor just for writing their novel.But because Emacs has these built-in ways tosupport managing your to-dos and all that stuff,it's very easy just to stuff that task in there.Have a quick shortcut to go to your to-do listand put something in. Then it gets out ofyour brain so that you can try to focus on thething that you're trying to get done.That's my quick underappreciated...actually, a lot of people really appreciatethis, but it's one of those thingspeople coming to Emacs from other editors mightnot immediately catch on to.Prot: You might not understand theextent of how valuable it is.It's the gift that keeps giving, basically.Sacha: Yeah, yeah.When your to-dos and your notes are just a coupleof keystrokes away, and they can save the contextof whatever you were looking at.
4:58Kill ring
Sacha: There are all sorts of other smallconveniences that Emacs has that also help withdistraction and focus.For example, the kill ring.It's such a simple thing, right?Prot: It's super simple, but super useful.Just to say on the kill ring, it has beenpart of Emacs for several versions now, but it'snot obvious.If you type M-y without C-y beforehand,you get completion.So you can select something that you had in yourkill-ring like a few kills ago.Clipboard navigation,which is something that you don't see right away.Sacha: If people are comingfrom outside Emacs and they're like, "What is thisthing that you're talking about?"People are used to having a clipboard, right?As soon as you copy something, your programforgets the thing that you previously copied.On mobile phones now, if you presspaste, you can see a selection of theprevious things you've copied before.It's like that, but larger.Sacha: Prot points out: you can use completionwith it.So M-y is yank-pop I think?What I find useful about this issometimes I'll copy something because I want togo paste it somewhere else, and then on the way tothat somewhere else, I get distracted by something,and I need to copy that, but I know that thekill-ring will have the other copies that I meant toput somewhere else.Prot: By completion here, we mean youcan type and match that thing, narrow down to it.Prot: You don't have to go searching for it and,"Okay, which one exactly is it," right?Prot: You can find it more easily.
6:50Registers
Sacha: Registers.It's the other thing that I like to use when Iknow that I'm copying several things and I needto paste them, possibly in different order.Sacha: Again, that's another thing that people arelike, "What is this thing, even?"Do you find yourself explaining registers topeople who are new to Emacs?Prot: Yes. Registers issomething that is underutilized, because of course,why would you need them when you can have akill-ring with a history, right? Why do I need tostore things in a register when I can just havethem one after the other in the kill-ring.The answer is because if you do something moreadvanced, such as with a keyboard macro,it will always be correct.It's precise.It's not "Give me the last thing on the kill ring,"or last thing minus two or whatever.Give me that, right,and you specify what that is.It's an expression of intent.Prot: Plus more advanced things,like incrementing a number or whatever.I think that's super specialized.Sacha: I don't even use that very much,but I know some people who use thatto great effect.So that's one of those little Easter eggs foradvanced users.If you're watching this and you're like, okay, Iknow about these built-ins, but there's more.Emacs has this fractal complexity.It just keeps getting more interestingthe more you dig into it.Okay, so, registers.Registers can store text that you're copying,but they can also store other things.I think, like, do you use them for windowconfigurations, Prot?Prot: I have used them for framesets:frames and their window configurations.If you have three frames and they aresplit in different ways, you restore that.Sacha: You can do all of that withjust one register.Prot: With a register, yeah.I have created another register of mine justto see how it works, where it saves afile with a specific location,but it's supposed to be in memory,not like a bookmark.I did it just for testing.Sacha: I have that too.I use registers to files so that I can jump tothings like my Emacs configuration or my notes orsomething like that.I use that instead of bookmarks so that I canjust have a keyboard shortcut go straight to thatregister.I can do the [jump-to-register] and then I can justeasily press one more keyto get to the file that I want.So registers, again, if you're not used to Emacs,this is a built-in that's got a lot of featuresfor helping you save text to things, especiallyif you're going to use them in keyboard macrosbecause you can say, okay, insert text A and theninsert text C and then insert text B. But you canalso use them for other things like frameset,like the way that your windows and your buffersare arranged, or files that you want to go back to.
9:58Narrowing
Sacha: Another built-in that I find really helpful formanaging my focus and distraction is narrowing.I get distracted by all the other stuff, or Iworry about accidentally revealing privateinformation when I am streaming, or something else.So instead I narrow it to just the task that I'mworking on or just the function that I'm editing.That's super useful not only for keeping mefocused, but also for making sure that my changesdon't affect more text than I mean to.If I'm using substitute.el... You can select theregion, and a lot of the functions in Emacs willoperate only within that region.But reselecting the region several times, if youend up needing to do multiple operations, it's abit annoying.So instead, I'll just narrow and then it can workon the whole thing.Prot: Yes. When you narrow, you canalso be less careful, in a sense.Like, you do a query-replace,when you do !, it means yes to all,but if you are in a narrowed region,yes to all means only withinthat portion of the buffer.So if you take care tonarrow to where you want to be,then okay yes to all, you don't even have to check.Sacha: And I think this isunderappreciated enough that, in fact, if you tryto use… Is it C-x n?Prot: That's the prefix key.C-x n for narrowing.Sacha: The first time Emacs willsay, are you really, really sure?It's one of those disabled commands, right?You've got to enable it for yourself.You've got to say, "Okay, I know what I'm doing.I'm not going to panic if the rest of my filedisappears."I know it's there.I'm just choosing to focus on it.I think it's actually available off the menu aswell, but I haven'tused it off the menu bar.Prot: Yeah, I don't use the menu, so Icannot tell.But I remember that prompt,"Are you really sure?"It's disabled by default.Please make sure you know what you want.Sacha: Keyboard shortcut.That's the way to do it anyway.Prot: The thing is that I do use it extensively.
12:04org-narrow-to-subtree
Prot: Narrowing, of course, is generic.,Org also has its own narrowing.The most common one is [org-narrow-to-subtree].
12:13narrow-to-defun
Sacha: Narrowing to defun feels easierthan trying to mark the function before searchand replace.I love narrowing.In fact, I narrow to functionsor sets of functions a lot,because I do a lot of work withwith Javascript in HTML files,just a single file HTML that I can upload.It's got CSS and regular HTML in it as well.But I often just need to copythe particular snippet of JavaScriptso I can paste it into the console asI'm making changes.I have a function thatlooks for certain text:"start of focus", "end of focus".Then it narrows to that section, which mightinclude several functions.Then I have another keyboard shortcut thatjust copies the entire buffer and adds a littletext at the end, so I can run whatever function Ineed to test.I can paste that into the browser.Narrowing either to one function or to apredefined region or whatever else is very useful.Prot: Yes, very nice.
13:19Indirect buffers
Sacha: Then people are like, yeah, butwhat if I want to narrow to twoparts of the same file?Prot: That's why you have indirect buffers there.Sacha: It's Emacs, of course there's a wayto do it.Indirect buffers is another one of thosebuilt-ins that's a little hard to wrap your headaround, because you're like, okay, you're openinga file twice, but you can have it narrowed to adifferent part of it, or you can be looking at adifferent part of it, or you can even have it ina different major mode.Prot: Yeah, yeah.And the point, like the practical one, is thedifferent levels of narrow, really...The most common one, I mean,where it's like, okay, you focus on this headingand now you focus on this other heading.Sacha: I'll often split my buffer if Iknow that I'm not going to narrow.So that way, if I need to refer to two parts ofthe file at the same time, I can have one windowfocusing on one part of it and the other windowfocusing on the other part of it.It might even be a different frame.And that way, I don'thave to keep switching back and forth.I don't have to scroll up and down all the time.I can just look at one and then look at the otherand arrange my windows and my desktop as I see fit.But if you want to do something more complicated,like more narrowing or different modes orwhatever, then cloning an indirect buffer is theway to do it.
14:50Undoing within a region
Prot: I don't know if you have this,but because youmentioned the region earlier, I will say it.Maybe you have it somewhere, I don't see it there.You know regular undo in Emacs and how it works,but when you have a region selected, undo worksin the region.So you make a change here, you go make somechanges up there, you come back here, you markthis region, undo only works here, it doesn'twork up there anymore.Sacha: Oh yeah, that's definitely abuilt-in that people will benefit from if they developan intuition for it.If you've made a bunch of changes to your fileand you notice that something's wrong in justthis section, you can select the region and thenundo within it to just fix those things.Those are some of the things that I've thoughtabout for focus or distraction or getting temptedto go down rabbit holes.Do you use any of the other Emacs built-ins tohelp you with your tendency to dive really deepinto something?
15:53Bookmarks
Prot: So the other one would be bookmarks.You mentioned it already,but it really is worth having it there,because the nice thing with bookmarks is that notonly it's a way to go to a place, but you alsogive it a name.So the counterpart...Like you said, okay, I have a key to quickly goto my init file, for example, my configuration file.But what if I want to have something by name thatdoesn't quite fit nicely in all the keys, right?Then I can have a descriptive name.Maybe it's long.For example, my notes for my meeting with Sacha,which is in mid-June, blah, blah, blah, right?I can have a long name like that, whichis descriptive and gives me context.Then I use a bookmark for that.Sacha: And that's a great built-insolution for the general problem of finding yourway around.So in case you're trying to find your way arounddifferent files or different projects ordifferent places in various files, bookmarks aregreat for that because you can give it a name.That means you can file more things than will fiton your keyboard.Kind of an advanceduse of it, I was talking to Benin the previous Emacs Chat aboutSo he bookmarks Elfeed searches,and based on his naming convention,if he names his bookmark a certain way,then it becomes available forthese other functions that he has.So if you have a naming convention for yourbookmarks, you can do other things with it fromEmacs Lisp.Prot: Yeah, exactly.That's the more advanced power user thing.It's just data and you have access to it.
17:41isearch
Sacha: Going back to something a littlemore basic for the problem of finding your wayaround, I think that isearch is one of thosebuilt-ins that people coming from a differenteditor might not think of using."Find in page" is an annoying experience in abrowser or in other editors.You have to go to the menu, you do it, and thenthere's things you have to click on in order togo to the next one or the previous one and soforth.But isearch lets you just keep typing and thenyou can just press the isearch shortcut again,C-s, to search for the next one, or you cango to the previous one very easily.So isearch is great.
18:21Tip: Add a counter to isearch
Prot: Yeah, yeah, it is.I think one nice quality of life improvement toit, which again is several Emacs versions old, isa counter.Like it shows you are on number 3 out of10, for example.You have a sense of where you are going.Sacha: Otherwise, I find I just wraparound to the beginning and Itake a moment to reorient myself because it haswrapped around.The other thing that I want to point outrelated to isearch as well is using it to helpyou mark a region.This is something that people aren'tused to because in other editors, you highlightthings with your mouse, right?Here in Emacs, we say, okay,press C-SPC to sayyou're going to start a region,and then just search for the end of the region,navigate to it somewhere, andthe text betweenwhen you press C-SPCand where your cursor is now,that's the region.Prot: Yes, exactly.
19:26C-x C-x (exchange-point-and-mark)
Prot: On this note, C-x C-x.By default, it’s exchange-point-and-mark.Which, if your cursor is here and where youstarted is up there, it moves the cursor up thereand now where you started is down at that point.You can expand the region both ways.You can keep switching and expanding.Sacha: I have never thought about using itfor expanding the region.I usually just use it to confirm that, yes, I amactually selecting the parts that I meant toselect.Because by the time, of course, I've found thething that I wanted to end the region with, I'veforgotten or I'm not entirely sure I have theright start.So I was using C-x C-x toquickly verify and have everything nicelyhighlighted.But expanding the region, yeah, that's a thingyou can do with it.Prot: Yeah, yeah, of course.Now it's obvious, right?But it's something that you may notice bymistake, by accident.Sacha: [interrupted by life]@charliemcmackin4859 says, "I love that you can make thosemarking tricks part of a keyboard macro."
20:55Popping to marks - going back to where you were
Sacha: Oh, the other thing I want to say with marks isyou can also navigate by mark.C-x SPC?Prot:C-u C-SPC.I think it’s pop-to-mark is the concept.Sacha: Popping to mark.We'll just go with the concept because people cansearch for the key binding.Which basically means for all the places whereyou were before you went off searching forsomething else or doing some other command,you can go back to those places in sequence.I think there are even some commands to letyou easily navigate through all the placesyou've been previously.That is a thing that you can do with Emacsbuilt-ins.It's called popping the mark.It lets you revisit places.Prot: Yeah, yeah.Another point related to this and also related toyank that we said earlier...
21:49Selecting what you just pasted
Prot: Imagine you have copied something and you arepasting it now in your Emacs.Then what you want to do is select it, maybeto do something with it, such as tomake it all up case or whatever, right?Instead of selecting it manually, you can justdo C-x C-x. Because when you pastesomething or when you do I search or whatever, ithas the effect of updating the mark.Then you can work with that.Sacha: Yeah, that one I use fairly often.Also, that way, you can easilysee what it highlights, the part that you've justpasted, and then you can do your otherreplacements or uppercasing or whatever elseto it.
22:33Indenting pasted or selected text with indent-rigidly
Prot: The nice part for this is theindent-rigidly,C-x C-i by default, where you can nowhave a region of text including an implicitregion between mark and point, and you just shiftit around, literally left or right.Try it.It's very nice.Sacha:C-x C-i.I think you can even use the arrow keys tomove things,so you can just nudge it until it looks right,which is great because sometimes, when you pastethings, the indentation isn't the sameas all of the rest of your stuff.You might want to put it all the way into anOrg list or whatever else, code block, whatever.Prot: Okay.Sacha: So C-x C-x, very handyeven after you paste.
23:24Popping to mark after xref or imenu
Sacha: Oh, @hmelman also points out the fact thatthings like xref or imenu push the last locationbefore jumping means popping the mark is an easyway to go back from various navigation mechanisms.In general, if you have navigated away fromsomething using some magical Emacs command thathas taken you far from where you are, you canalways find your way back home or back to whereyou were by popping the mark.I think there's even a distinction betweenpopping the mark in your bufferversus popping your global mark.You can go to a different buffer that you werejust in if you wanted to.
24:05Adding other packages like consult
Prot: Very nice.Many of these are also augmented bypackages. When you install a package, it doesn'tintroduce completely new functionality. It adds toexisting one. For example, the consult package,which is very useful, very nice, has something todo with what we just mentioned. Like,navigating the mark in a visual way,so you get to see it.Sacha: @hmelman points out that local and globalmarks are useful to navigate through.Check out all these other packages for addingextra functionality around that.
24:44Tip about indicating isearch wrapping
Sacha: @matthewjorgensen9115 says,"thinking about isearch wrappingaround search,gwhen you get to the bottom of your file, whenyou're isearching and there's no other matches tobe found, it will by default wrap you around tothe beginning of the file so you can keepsearching from there."Matthew says you can either have scroll toposition to know the direction(it also indicates the position in your mode line),or you can have your mode line flash to see itmove from last to first.I don't have that configured.I should look into how to get that configuredbecause it's like all these little things, right?But sometimes you don't needto make a big navigational jump.You just need to move forward by a little bit.
25:26Navigating by sentence or s-expression
Sacha: Emacs has built-in shortcuts for navigatingby expression, maybe things inside theparentheses or things inside the quotes, as wellas natural language shortcuts like navigating byword or by sentence.Those are some very useful built-ins that arewell worth learning the keyboard shortcuts for.Prot: Yes, indeed.Of course, we call themS-expressions and the terminology of the commandsalludes to Lisp, but they work in otherprogramming languages as well.For example, there is theforward-sexp, but it works in other languageswhich don't have this Lispy syntax.Sacha: So if you skipped over that part ofthe tutorial or the manual, go back and read itbecause it can save you some time.In a pinch, it will also help youmake sure that your parentheses are matched upcorrectly and you go to where you expect them to go.There are other ways to make it easier to matchup parentheses or braces or brackets or quoteslike [ show-paren-mode ] or whatever.Sometimes I just go forward and back to seewhether I end up in the right place.Prot: A small trick here,if you are writing specifically Emacs Lisp,there is a very common mistake of addingan extra parenthesis, and it says "end offile during parsing", or one less parenthesis, whatyou can do with a combination of keyboard macros...You go to the beginningand you do C-M-e to go to the end of the defun,and then, in a keyboard macro, you keep doing that.Next, next, next, end, end, end, right? Until it stops,and you know where your error is.Sacha: Oh, and I should tell people, ifyou give the execute-kbd-macro a negativeargument, it'll run until error.So you just do thatand it'll drop you where it ends.You don’t have to manually press e 500 times.Prot: Exactly.The "run until error" happens when you are in anarrowed region as well.Error here means end of region, end of buffer.Sacha: I should point out in the specificcase where you're trying to hunt down a strayparenthesis, you should also just usecheck-parens, which will tell you.Prot: Of course.
27:45Navigating to other errors
Sacha: And for other errorsnot just limited to missing quotation marks orparentheses,it's well worth taking the time to set upflycheck or flymake or whatever error checkingthing you want to use, because then you cannavigate to the previous and next errors aseasily as you would with keyboard shortcuts.If you get the hang of doing that, you canalso use the same mental model to navigate through...If you're doing a keyword search with grep, thenyou can use the next-error, previous-error
toalso go to just the next match or the previous match.Prot: That's very useful.
28:29Tags
Sacha: I am not using tags nearly as muchas I probably should for navigating symbols.Prot: Tags, yeah, in the context ofprogramming.Me, I haven't used that, no.Sacha: Oh, yeah?I guess because you primarily work withEmacs Lisp, it's easy enoughto find the definition from there.
28:47Imenu
Prot: But imenu is the other one, along those lines.Sacha: That's interesting.You don't use the menu bar, but you use imenu.Prot: Yes, imenu is useful because, ofcourse, it's with completion.Now, I should say here, of course, that thedefault imenu has this concept of going in steps,but you can flatten the list, which is moreinteresting for the purpose of completion.I believe what I'm saying is the case, but Idon't remember anymore.But you can have a flattened list, at which pointyou navigate the file with completion.Sacha: I should try that because I reallylike the way that Org, when you're navigating bythe outline, you can also configure it to flattenthe list so you don't have to complete theheading and the next setting and all that stuff.@hmelman says you don't actually need flymake for theerror navigation thing.You can just use next-errorand previous-error which works withcompile and grep and occurand a bunch of other things that have thesame convention.So yes, if you use the M-x compile command torun whatever your compilation step is, it willparse the output of many compilation systems,programs, and it will let you jump to the nexterror.It will also even show you the errors, I think.Anyway, so you don't need flymake.Flymake just gives you the squiggly underlines.But you can use next-error right away.Prot: Yeah, yeah, yeah.Flymake is more narrow.Yeah, correct.
30:19Projects
Sacha: I think projects and project-basednavigation is another big chunk of Emacs built-infunctionality that is useful for people who havea hard time finding their way around.You don't have to manually find each file.You can set up shortcuts so you can say, I wantto go to this project.Then from within this project, I can find afile very easily.Prot: This is indeed verypowerful. The thing is you don't have to alsothink in terms of the structure of the project,like the tree structure of the project, because ifyou find the file in the project, itwill flatten the structure for you, so then youuse completion to find it or find the directorywhere something is. Of course, you can stilluse the tree view as well.Sacha: This is great becausefor example, in Java projects, thedirectory structure gets very deep because theyhave to be their domain name andpackage names and all that stuff.Just have either project or projectile index allof your files for you, and then you can jump to afile by name anywhere in your structure.You can tell it also to ignore certain files,which is handy so that you don't have to go intoyour node-modules.That would be silly.Prot: Yeah, that would be a nightmare.Sacha: Do we have basically the Emacsbuilt-ins for finding your way around wellcovered here, or other other recommendations thatpeople should go check out?Prot: These are already very useful, yeah.Most of these, if not all, are augmented by packages.So the core functionality is there, and then youcan do more stuff with them.
32:10Putting projects in tabs or frames
Prot: For example, with projects, you may want to havean arrangement where you put them in separatetabs, and then you use a package like tabspacesso that each tab has its own buffer list, ormy package beframe so that you put them inseparate frames.Each frame has its own buffer list,so that basically when you search for buffers,you only see those related to the project.
32:35Tabs
Sacha: I am not using tabs nearly as muchas I probably could,so that is one of my underappreciated Emacsbuilt-ins here.I'm getting the sense that people use tabs tosay, okay, this is the set of windows related tomanaging my mail, or this is a set of tabsrelated to this project.This is a set of windows related to this project,or this is a set of windows related to managingmy notes about something.Is that what you use tabs for?Prot: I seldom use them.I use them specifically only within the contextof popping into a Magit interface.So I have my project that I'm working on.Let's say it's split in three windows.And then I want to leave everything intact andjust go into Magit to do some Git operation.I configure display-buffer-alistso when I do Emacs Magit,magit-status or whatever, it goes in a new tab.Then I leave my work where it is.I do the git thing,then I quit those. I'm back to my layout.Sacha: I know you're agood advocate of checking outdisplay-buffer-alist and all the wonderfulthings it can do.I should definitely look into having it set up atab because that sounds a lot nicer than tryingto remember, okay, I need to save my windowconfiguration to register and then do this thing.I have it set up actually so that I canwinner-undo in order to get back to my previousconfiguration.But of course, if I need to flip back and forthbetween two different views, like Magit andmy project code, then a tab would work muchbetter for this purpose, I think.Prot: Yes, and it scales better as well,like if you need to have three tabs or whatever.Sacha: Or a new frame.But sometimes managing frames gets a littleannoying too.Prot: Of course, of course.There are pros and cons.
34:41Navigating frames
Prot: Speaking of frames, one nice thing is that thereis completion again to select frames.So I forget how it's called.[ select-frame ], I think, is the command.If you have lots of frames and you don't knowwhere they are, you can use completion for that.If you want, you can also name frames.I believe it’s rename frame. [set-frame-name]I forget now the command.Basically, you can give it a specific namerather than it changing the name all the time.So you can say, OK, this is my superimportant note for our livestream, right?That's the frame for you.Now you can find it.Sacha: I should look into that.I also underutilize frames because for the mostpart, I have a keyboard shortcut like Super 1which jumps back to Emacs, raises myEmacs window.But it doesn't work so well if I have multipleEmacs window, like multiple Emacs frames.If I can figure out how to get mentallythrough that or if I switch to EXWM as my windowmanager,then I'm sure that managing multiple Emacs frameswill be a lot easier.But at leasttabs, I can probably use within that one frame inorder to manage different windows.Prot: I would say tabs is the first thingyou want to check.Frames is a little bit more... You have to changeyour mental model a little bit.
36:07These navigation shortcuts work for prose, too
Sacha: @hmelman has one more tip toinclude in this section on finding your wayaround.You can use these S-expression commandsin prose too.Like for example, C-M-u or
backwards-up-listmoves you out of a quote or a parenthesisand then you can C-M-e to go to the end of it.So even if you're writing, for example, a novel,and you're saying, okay, I want toget out of this quote and go to the next sentence,you can either isearch to the start of it,or you can go up out of the quote and thengo to the end of the quote.Also very handy to learn the commands for killingan S expression [ kill-sexp ],which again also works withother stuff like quotes or parentheses, becausethen you can copy and paste things or you cankill it.You don't have to paste it back.It's just you delete it and then you typesomething else in.It's fine.Prot: Exactly, exactly.And one of those is the mark-sexp, whichis very useful.
37:09follow-mode
Sacha: Oh yeah, oh yeah.And @matthewjorgensen9115 shares:
follow-mode allows the samefile with multiple frames like a book.So follow mode can work with two, three or morewindows.You have an ultra wide, right?So like, okay, you can have several columnsfollowing the same file and you can scroll andall of them will scroll in sync.Prot: Yeah, yeah.It's quite nice.Quite nice.Sacha: I forget, does follow mode workwith different files?Prot: With different files?I don't think so.Like kind of a scroll lock for all windows?Sacha: Yeah, yeah, yeah.Prot: I don't know.I don't think so.I haven't tried it.Sacha: Worth looking into. [scroll-all-mode]
37:50Ediff
Sacha: If you do find yourself needing to compare onefile with another manually, then maybelike ediff?Prot: Ediff would do that.You would have them side by side.But the thing with Ediff is that you don't get ascroll lock for both.It's only navigation through the differences.So that wouldn't be exactly that.Sacha: For the purposes ofcomparing, Ediff will let you compare two files,but you can even use it to compare two buffers.However, Prot does have some recommendations inthe one on the defaults that you shared before onhow to make Ediff more manageable.Prot: Yeah, I think by default it's notintuitive, because by default, when you do Ediffwithout any configuration, it will display itspanel in a separate frame.If you have never used many frames, that'salready your first problem.Like you don't even know what happened.The second problem is that the layout will be oneabove the other, which depending on your screen,you have like a wide screen, so it's not as easyof a layout.Then you have to figure out where the otherframe with the panel is.Basically two variables where you change themand you have the panel at the bottom, the controlpanel and then file A here, file B there.And of course you can do it with three filesas well.Sacha: I will find it and put it in theshow notes.Matthew also points out the following also workswith centered-cursor-mode [(it’s a package)],which will keep thecursor position in the middle of the frame.So I can't remember whether there's also like ascroll lock or whatever.Prot:scroll-lock-mode.Yeah, there is `scroll-lock mode.Sacha: Or there was anotherEmacs built-in that someone mentioned thatscrolls it one line at a time, keeping itcentered, I guess, which the person found veryuseful because their cat was sitting on theirlaptop.So moral lesson is: learn about the Emacs built-inbecause you never know when a small mammal willbe obscuring half of your screen.You can still use Emacs.Which actually is an interesting segue into thisthing about discoverability because Emacs isquite unlike many other editors.It is very well documented and if you can figureout how to navigate and find that documentationand even how to make this fun for you, then youcan do all sorts of interesting things with it.Okay, so self-documentation.I love telling people, okay, you can just pressC-h k or describe-key to describe
anything.You can C-h f any function.You can, you know, C-h v any variable.describe- whatever is great.Of course, adding C-h to the end of thekeyboard shortcut that you've started but you'veforgotten how to finish, especially if you'veturned on which-key mode,is great for listing the actual shortcuts thatstart with that sequence.Prot: And even without which-key, it willput all those shortcuts in a Help buffer,and it will show the key and the name of thecommand.Of course, you can click on the command toread about it.Sacha: Someday I think it would be amazingif Emacs comes with a completion interface that'seasy for people to understand and get started with,but in the meantime, if you don't already havecompletion set up, that is well worth taking thetime to figure out.Prot: Yeah, yeah.The built-in one has improved tremendously.I mean minibuffer.el herehas improved tremendously over the various recentversions.But you still need to be aware of all the useroptions to configure it.So to get, for example, a single column viewinstead of a grid with 100 options...That requires some effort.Out of the box, if you really want somethingthat is built into Emacs and does completion in away that is fairly easy to understand, it wouldbe icomplete-vertical-mode or fido orfido-vertical-mode.
42:12Calling functions by name
Sacha: Another thing that Emacs doesdifferently that might be good for people tolearn about is that in Emacs, it is totally okayto not remember the keyboard shortcuts foreverything or not use the menus for everything,because not everything will fit in the menuseither.If you kind of remember the name of the function,you can use M-x and possibly completion to gorun that function,which is helpful because sometimes knowing thewords to call a function is a lot easier toremember than remembering the shortcut for it.Prot: Exactly.And I would say completion...
42:52Completion
Prot: If you have to configure one part of Emacs,it's completion.If you improve that part of it, it will help youeverywhere.Like we were saying earlier about bookmarks, ithelps you there.The kill-ring, it helps you there.Finding files, it helps you there.Switching to buffers and so on.Like what we are now talking about.It's always useful.Sacha: When you set up a completion, alsolearn how your favorite completion system letsyou put in things that look like they shouldmatch something on the list, but you actuallywant just the partial part or just the blank part.For example, in some systems, you pressM-RET or M-p to send what you already
havethere instead of selecting one of the completionoptions.This is helpful because sometimes you'll wantto name a file something that is a substring ofanother file and you want to be able to say,yeah, that is actually what I meant, not thecompletion part.Prot: Yeah, yeah.I think that's the only rough edge with most ofthose, yeah.Where you have to be mindful of that or, youknow, I have to select the prompt or I have totype a special key for this edge case.Yeah.Sacha: Once you get that sorted out andyou've drilled it into your fingers, it's very,very helpful to have completion sorted out.
44:13Manuals
Sacha: Emacs also comes with extensive manuals.You like to write very thorough manuals for yourpackages, which I also appreciate.Flipping through manuals for fun is somethingthat we've discussed in previous...This is such a great practice.You learn something new every day.I was going through the Emacs manual inpreparation for this conversation and I was justhighlighting things that I need to dig into.Prot: It's very useful and again to pointout completion.C-h R is how you can search for themanual of a package.Like for example, I'm interested in Org.C-h R, Org.I find Org from anywhere, right?C-h R and then I will search forsomething else, right?Elisp, for example, to go to the Emacs Lispreference manual.Again, very useful.From inside the manuals, g to go to achapter, also known as a node, i to go to atopic, an index, and m if you want, but g
and i.Just think of g and i. Very, very
useful.m is also useful to navigate the menu of thecurrent node.Sacha: I use s also for search.Prot: And there's for researchthroughout, yes.Sacha: Yes.I have not been using C-h R.I have been using C-h i to look at the wholelist of info manuals and then using m or isearchlike a newbie.Prot: That works.The problem with that is that if you have alreadygone into a manual,C-h i will take you back to that manual.So you have to click it and then start again.Sacha: Okay.Alright.Well, I'm learning new things.Prot: Nice.
45:57Menus
Sacha: Okay, you mentioned you are not afan of... you don't use the menus and I know alot of people...Prot: But I appreciate that.And in one of my... oh, in a coupleof my packages I have menu entry.Sacha: Yeah, and I know a lot of peopleturn the menu bar off in their"this is how you configure Emacs" sortof tutorials.But if you are new to Emacs, and even ifyou're an intermediate user, I stronglyrecommend, sacrificing that tiny sliverof vertical space for the menu bar,because it's a great way to discovercommands that are related to yourparticular major mode or other things.It's just fun to go through it and see what'sbeen deemed worthy of including in one of thosemenus.There are some efforts now to get the right-clickmouse menus to also have lots of interestingoptions, but definitely the menu bar at the top,which can also be accessed if you use F10 if youdon't want to use the mouse.The menu bar is even working on terminal,which is nice.So yes, menu bar at the top has a lot of usefulsuggestions for discovering things.Prot: Yes, yes, excellent.The part you mentioned about key navigation,that's also good.You may be like, don't want to usethe mouse.There you have it.You don't have...Sacha: And speaking of key navigation, ifyou press C-h k, which is describe-key,
itwill work on menu items as well.If you're finding yourself always going to themenu to do this thing, sometimes the menu itemsare not named the same as their commands, but youcan use C-h k to find out what that functionis and what keyboard shortcuts it's bound to.Then you can call it with M-x directly, oryou can memorize the keyboard shortcuts.
47:46Automation - abbreviations
Sacha: Okay, shall we move on to automation,for which Emacs has a ton of built-in things?Using abbreviations and things like that isactually something I picked up from reading yourconfig, I think, because you use abbreviations a lot.Prot: Yeah. Very nice. Very useful.Even for basic things.For example, I want to write, you know, myfancy French expressions, like, this is sodéjà vu, you know?I want to have the accents correct.I just write deja vu with English, and then Ihave the French equivalent with all the fancyaccents.Stuff like that you can do, like...something you keep misspelling the whole time youactually do it, right, something that is with anannoying spelling, like annoying capitalizationlike LaTeX. Nobody knows how that is written. Youjust write it latex, all lowercase, and then expandto whatever it should expand. This sort of thingis very useful. Of course, you can just havesome short text which expands into very longtext.Sacha: We should also point out if youtype something that is normally an abbreviationlike LaTeX, but in this case you actually want towrite the word latex, then how do you do theabbreviation without it being expanded intowhatever that is?Prot: Of course you would rather avoidthat situation with your abbreviation. It wouldn'tbe like that, but otherwise you will have to undo.When you do SPC and it expands, you undo.That is a little bit annoying, for sure. But Iwould say, just make sure to have abbreviationsthat are not ordinary words.They are a little bit contrived, so you don't getfalse positives.A good use case here, like what I have in myconfiguration, like you can have yourabbreviations behind acharacter such as the semicolon.Then of course it's very unlikely that you willhave semicolon later.
49:56Quoting the next character with C-q
Sacha: The other thing that you couldpotentially do is use C-q to quote the nextcharacter literally.So here for example, I have ot expand to thecurrent time, but if I say otC-q SPC, this
helps.And in general, this idea of C-q to quotethe next character is also useful in other placeswhere you might, for example, need to add aliteral new line to a search or something like that,or a literal tab.
50:31Mapping abbreviations to code
Sacha: The other thing that I want to add toabbreviations here is your abbreviations are notlimited to just text.You can use them to run things, which means youcan use them to run things that expand to text,or I think you might even get away with usingthem to run commands.So it's pretty limitless.Prot: Yeah, yeah.Of course, it's how determined you are to writecustom code for that.Sacha: Or how resourceful you are infinding other people's custom code that you cancopy, at least.Good motivation to learn Emacs Lisp.I do not remember if Yasnippet is built-in.It feels like it's built-in.Prot: No, but it's one of those thatbasically everybody uses.Yasnippet or Tempel.Sacha: A couple of questions from chat.When highlighting parts of the manual, how areyou doing this?In bookmarks, bookmark-region, using Org Remark,other ways?I was doing this at the playground the other day,so I just had it in my iPad and I had it in oneof those graphical note-taking things and I washighlighting with the Pencil.But I've heard good things about Org Remark,which is a package.
51:51Taking notes with org-capture
Sacha: You can also use just org-capture if you’rereading the manuals from within Emacs, which youcan.If you org-capture, you can even select sectionsof the manual and it'll automatically save thatin the capture template along with a link back towhere you were looking.This is great.
52:08Navigating back to captures or refiles
Prot: Since you mentioned org-captureand we talked about bookmarks earlier, when youdo org-capture or org-refile, it stores
abookmark.You can go back to the last capture, the lastrefile.Sacha: Yeah, yeah, which is handy.Also, you can use org-refile to navigate your Org
files.In addition to using it to jump to the lastthing that you filed because you were like, "Oh,yeah, wait, I forgot.I want to add more to that note,"you can also use it to jump to any of yourprojects, for example, or any of your notes,assuming you’ve set up your org-refile-targetsappropriately.Okay, @RandCode has question.Does Emacs have a grammar checker like Harper's LSP?I know there are packages that people can use towork with Harper and other things.Do you know of any other built-in things?Prot: Built-in, it's flyspell, butthat's not grammar.That's spelling.Sacha: Okay, all right.Prot: I cannot think of something.No, I don't think there is for grammar.So Harper or anything like that would plug intoFlymake.Sacha: @greggr0th has a question.What are your favorite completion plugins?Prot: Yeah, I think it's really vertico.I prefer it over the built-in options, overicomplete.So it's vertico, and then with that, I wouldsay, at minimum, orderless.So vertico and orderless, at minimum.But then, of course, if you want a little bitmore, which is very useful, Marginalia, Consult,Embark, maybe I'm forgetting something, save-hist,it's built-in.But yeah, those, those for sure.
53:49dabbrev
Sacha: @hmelman says dabbrev for dynamicabbreviations is underrated.You don't need to predefine them.You just type the start of a word or symbol andtype M-/, and it will search the buffer forsomething starting with what's on the left sideof your point and then expand it.I can't remember if it's dabbrev or hippie-expand,but you can also set it up so that it can trywords from other buffers or other things thatyou've got or contacts or whatever.Anyway, so dynamic abbreviations.If you search for dabbrev and if you look also forhippie-expand, you will find lots of things thatyou can configure to fit your particular workflow.So you can expand abbreviations without having todefine them.Prot: Yeah, yeah, yeah.Super powerful.Super useful.I use it more than tab completion, you know, likewith core.I use dabbrev more.It's very nice.Yeah.
54:44Keyboard macros
Sacha: Okay, so we've mentioned keyboardmacros very briefly, but this is another verypowerful chunk of things that people might not beused to if they're coming from an editor that isnot Emacs.So keyboard macros, what's kind of like the thingthat we can use to explain?How do we explain it to people who are new tothis?Prot: In its simplest form, you recordwhat you type and you can play it back in itssimplest form.But the thing with Emacs is that you don't justrecord typing motions, typing actions.You also record all the Emacs motions.You can have a keyboard macro that includesstuff such as move to another window or create anew split or whatever.You can do more advanced things like that.This has very nice qualities to it where it'slike, oh, I just want to copy all these symbolsand move them to my shell buffer and then I willdo something with them,pipe it to something like a programoutside of Emacs. So it hasa lot of nice applications like that.Sacha: I think that if people can get thehang of: very carefully set up theirkeyboard macro, think what's a series ofsteps that I can do so that I can do the changeand then move my cursor to the start of where thenext change should be...For example, I'll start the keyboardmacro, I'll delete the word, I'll type insomething new, or maybe I'll paste in a registerI'll use isearch to find the next point at whichI need to do something.If you define your keyboard macros like this,then you're giving yourself the ability tointeractively confirm whether you're still on theright track and then make the change because thatway, it's not just like a search andreplace and you're hoping it all works out.Although the recent search and replaces are greatbecause they show you the changes.But for something that's more complex, especiallyif you're not used to regular expressions,keyboard macros can help youinteractively do it in small steps.Prot: Yeah, exactly.Of course, search and replace will be moretricky if you have to go through many files andperform multiple edits in each,because then the concept of regular expressionsbreaks down.You don't want to think in those terms where it'slike, I will have to make a change somewheretowards the top and then somewhere in the middleand then somewhere towards the end. Keyboardmacros combined with Dired combined with going tofile... Very nice.Just to say another thing about keyboard macrosis... Let's say you have written your very nicekeyboard macro. You're recording it, and somewheretowards the end, you make a small mistake.Keep going and then C-x C-k C-e toedit your macro.It's a text buffer. You just remove what youdon't want.Sacha: You can save these keyboard macrosas well.You can use them in a future Emacs session oreven turn them into your first Emacs Lispfunction.You can give it a name and you can run it that way.
57:52Editable grep and occur
Sacha: In the next three minutes before the kiddo runsout for lunch break, I also want to mention,since we talked about making changes in multiplefiles, that grep and occur are both editable.You can do your grep and you can search forthings.And then you can say C-x C-q which turns itfrom read-only to something you can change,then you can do your search and replace in that,and you can C-x C-q againand those changes can get put backinto all those different files.Prot: It's amazing.On this note, specifically for grep, if youedit many files with the grep edit mode that isbuilt into Emacs 31, it will not save them for you.So C-x s, instead of C-x C-s,allows you to save multiple buffers.And every time, it gives you a prompt and you cantype d to see the diff.Like, okay, what exactly did I change?If you have many unsaved files, d to see whatyou're about to save so you never make anymistakes.Sacha: Mm-hmm.Taking advantage of these diffing tools isgreat also.Even if you're new to Emacs or you don't have aprogramming background, if you find yourselfmaking changes to lots of files, I stronglyrecommend learning more about version controlsystems like Git and then using something likeMagit or even the built-in VC.If you use VC, you can use it and you have set upsomething like a git repository.You can use `C-x v =` to diff to seethe changes between your file and the previousthing that you had saved.Which makes sense so that you can see, okay,these are the changes.Also it means that you can experiment withdifferent changes.You can experiment with different ways ofwriting a paragraph or whatever, and you knowthat all of your previous versions are saved andyou don't have "really, really finalversion two."You don't clutter your directory with a lot ofcopies of the same file.Prot: But even if you don't have any ofthe version control system set up, a very simplething is diff-buffer-with-file.So you have a file you are working on and now youmake some edits.The buffer, what is in memory, is differentthan what is on disk.You can compare the difference between the two.Sacha: Okay, I'm going to try to wrap uphere because the kid is going to run and say hivery soon.Thank you so much for joining me.Of course, there's a lot more to talk about theEmacs built-ins, but I hope we've given a quicktour of some of the things that are definitelyworth learning more about and the situations forwhich they are absurdly useful.Thanks to everyone in chat also for coming andhanging out.I will post the show notes eventually and get thetranscripts sorted out.Thanks.Prot: You're welcome.You're welcome.Take care.Of course, good luck with everything.Didn't she show up here?Sacha: If she shows up, she will.It's inevitable.
1:01:01Emacs Carnival June 2026: Underappreciated built-ins
Sacha: Also, if folks are interested, even if you'venever blogged before, the Emacs carnival themefor June 2026 is "Underappreciated Emacsbuilt-ins," which is why we had this conversation.Feel free to write about something and eithersend [Ross and] me a link,or you can even send me the postand I'll post it on my blog with your name on itand other things like that so you can share yourappreciation for these built-ins.All right.Okay, I hear movement.I gotta go.All right.Prot: Take care, Sacha.Take care, folks.Goodbye.
protesilaos: Looking forward to this! Talk to you soon.
gr1maldi: Yo, and stuff.🙂
charliemcmackin4859: I just checked, there are 11 items in my kill-ring at the moment. Some of them are several lines long
charliemcmackin4859: narrowing to defun feels easier than trying to mark the function before search-and-replacing… I love narrowing
charliemcmackin4859: …and I love that you can make those marking tricks part of a keyboard macro
hmelman: both local and global marks are useful to navigate through
pratikmishra4073: just tried indirect buffer. didn't know it existed
hmelman: and the fact that things like xref or imenu push the last location before jumping, means popping the mark is an easy way to go back from various navigation mechanisms
matthewjorgensen9115: thinking about isearrch wrap around search losing your place. either have scrroll to posisiotn to know the direction and how far it was away, or have mode line flash to say it moved from last to first
hmelman: Don't need flymake for that just M-g M-n (next-error) which works with compile, grep, occur (I think).
hmelman: One I keep forgetting about, you mentioned using sexp commands in other languages, works in prose too. C-M-u (backwards-up-list) moves you out of a "quote" or (paren) and then C-M-e to the end of it.
matthewjorgensen9115: follow mode alllows the smae file with multiple frames, like a book. follow mode can work with 2 3 or more windows
matthewjorgensen9115: also works with centered cursor mode which will keep the cusor possion in the middle of the frame
RandCode: Damn I am late, hello everyone! 🙂
matthewjorgensen9115: when highlighting parts of the manual how are you doing this? in bookmarks, bookmark region, using org-remark? other ways?
RandCode: Does emacs have a grammar checker like harper's lsp?
greggr0th: What are your favorite completion plugins?
RandCode: Also, looking fresh Prot ;)
protesilaos: Thanks!
hmelman: dabbrev is underrated. You don't need to pre-define them, just type the start of a word/symbol and type M-/ and it will search the buffer for something starting with what's left of point and expand it
RandCode: There is so much to learn that I feel like I have been missing out on all of emacs somehow lol
RandCode: Since you mentioned built-in completion framewworks, how does the built-in (vertical) completions compare to corfu btw?
charliemcmackin4859: not grammar, but if you have a dictionary server running (like dicod on linux) emacs can be made to communicate with it to give definitions at point
RandCode: Ohh, that is a cool! ^
matthewjorgensen9115: virtico multiform mode allows custom settings command, for example for files I use grid and alphabetical, but vertico recommendations normally. This allows more value of completion knowledge
RandCode: Thank you so mcuh for this wonderful stream everyone!!!
I will join Sacha’s live stream this Thursday to talk about
underappreciated features that are built into Emacs. There are a lot
of nice things that are available out-of-the-box (plus many packages
that build on top of them). I am looking forward to it!
If you have a numeric keypad1, try this in the *scratch* buffer:
enable numlock and press the zero on the numeric keyboard
(Num-0). Then press the zero located between the alpha keys and the
function keys (0). Okay, you see 00, no big deal.
Why do I bring this up? Emacs interprets Num-0 keypress as <kp-0> while it interprets 0 as
0. This means that you could bind Num-0 to a function without
affecting the other 0. You could configure Num-0 to insert "zero" by
entering and evaluating this in the *scratch* buffer:
That's a trivial example, of course. But it implies that you can
have ten more keys to play with. Similarly, the arithmetic
operator keys on the numeric keyboard differ from the "regular
ones" that are grouped with the alpha keys. They can be bound
to functions, referenced
as <kp-add>, <kp-subtract>, <kp-multiply>, <kp-divide>. But
these also accept the standard C- M- S- modifier keys, which
gives you twelve more possibilities. This is true also for the
Insert key <kp-insert> and the Delete key <kp-delete> that
double as Num-0 and Num-., respectively.
I have a "Calc" key above the numeric keypad. Unfortunately I
can't seem to use it for anything in Emacs -- it opens the OS's
calc.exe program regardless of what modifiers I use with it. This is
a shame because it would be the ideal mapping for M-x calc. Perhaps
this can be altered in BIOS.
But I do use my Win key as a modifier (sometimes). And I've heard
that the Caps Lock key can be repurposed. These are topics for
other posts.
Daniel Mendler, who took over as maintainer of the world’s best RSS reader, Elfeed, has announced the release of Elfeed 4.0.0. You can read the Change File to see what’s new but the most important point for me is that the maintainership of Elfeed has successfully transitioned from Chris Wellons to Mendler.
When Wellons announced his retirement from the Emacs ecosphere, I, and I’m sure others, had a moment of apprehension. We all wondered if anyone could fill Wellons’ large shoes. I’m happy to say that Mendler has shown himself up to the task and is doing a great job moving Elfeed forward.
As I’ve said before, I consider Elfeed an almost perfect RSS reader. It’s easy to configure it to operate the way you need it to. One of Mendler’s changes that I really like is the ability to pop into EWW if you need to. I use it from the default Elfeed text buffer but also from the WebKit mediated display if there are too many ads and blinkenlights on the default page. As I’ve said before, I have a growing appreciation of EWW and am a bit surprised to find it becoming one of my go to tools.
The important point, though, is that if you’re an Emacs user who has an RSS feed, you should definitely try out Elfeed. You won’t, believe me, want to go back.
Emacs provides four useful status bars (mode-line, header-line, tab-bar, and tab-line), but each imposes different, inconsistent limits on multi-line layout, alignment, icons, and interactivity. svg-line (see code on GitHub) solves this by rendering them as SVG images, and normalizes a rich feature set across all status bars with a consistent configuration. svg-line works by defining a small rendering engine built on Emacs's native SVG support. Configuring status bars is easy: you simply write one :content function and call svg-line-activate. You can see my custom configuration of mode-line, header-line, tab-line, and tab-bar in my Emacs config.
Figure 1: Every *-line in this frame is one SVG image drawn by svg-line.
2. About
Emacs gives us four status bars, the mode-line, the header-line, the tab-bar, and the tab-line (*-lines for short). These are useful for providing a dynamic 'heads-up display', for important context, like what buffer you're in, the active major mode, and really any arbitrary thing you can define.
I'm a heavy user of the *-lines in Emacs, and I have them all enabled, but the issue that has plagued me is that, natively, each one behaves differently and each has unique limitations. For example, multi-line status (necessary on my small laptop) is possible, but only in the tab-bar. Right alignment is possible in the tab-bar, but only in the last line, and this alignment feature is only available in the tab-bar. I can display icons from all-the-icons in the mode-line and header-line, but not the tab-bar or tab-line. Etc….
What I really want is consistent behaviour and configuration across all these status bars, and I want the multi-line, alignment, and icons features available in all of them. It turns out that SVG (scaled vector graphics) is the key to solving this.
Inspired by Nicolas Rougier's dual-header gist, I built svg-line, which provides this experience by utilizing Emacs's built-in SVG rendering support. At first, this approach seemed like a hack, or abuse of the *-lines, or neglect of the built-in status bar behaviour. But I kept it and created a package because I was literally shocked how well this works and how native this feels (see the screenshot and video above).
Note that even if you only use the mode-line, svg-line is still useful — likely more so, since a single status bar has to render all your indicators on its own.
3.svg-line's Features
Multi-line everywhere, with per-row left/center/right alignment.
A tab-line that wraps overflowing tabs onto new rows instead of hiding them, including with file-type glyphs, a current-tab highlight, and an unsaved tint.
Clickable anything. Any segment can carry a left-click action, a right-click menu, and hover help with a highlight. This works uniformly across all four bars, including the otherwise-uncooperative tab-bar.
Icons as text. Using Nerd Fonts and an icon is just a character that flows with everything else. SVG rendering also enables a full-height "masthead" glyph option on status bars that can span multiple lines.
Dynamic and animated indicators: a buffer-position pie, progress bars, active vs. inactive styling per window.
It respects text scale. The bars track text-scale, re-rendering crisply instead of blurring.
A meta feature is that the configuration surface is uniform across all status bars, which is a pleasant improvement over the diverse configuration strategies for the native APIs.
4. Why SVG Works
When using svg-line, each line becomes one SVG image, and SVG images are more featureful than the native text engine:
It can be any height. Multi-row bars are now possible in every *-line.
Everything is placed at exact pixel coordinates. Left, right, and center alignment work identically on every row.
It draws whatever you want. Text, yes, but also wrapped tab flows, geometric progress bars and pies, and (with a Nerd Font) icon glyphs inline with the text, the same on all four lines. Anything you can render in an SVG (just about anything) is fair game.
The engine remembers where it drew. It can detect the mouse against those placements, so clicks, right-click menus, and hover all work on any element of any line.
5. Configuration
Configuring svg-line is deliberately simple. You write a :content function that returns rows, supply it to svg-line-define, and call svg-line-activate on the defined line. This configuration pattern is identical for all four bars. The engine has two layouts: lines (the default — rows of segments, used for the mode-line, header-line, and tab-bar) and wrap (a flow that wraps, used for the tab-line).
5.1. Mode-line
5.1.1. Simple mode-line
The smallest useful line is a single row: a label on the left, the cursor position on the right.
This trivial example clarifies the pattern: define then activate:
:content is the only required key: a function returning a list of rows. Each row is a (LEFT . RIGHT) cons, and each side is a list of segments — here just plain strings.
with no :background, :foreground, or :active, the line picks sensible defaults and is always drawn as active.
svg-line-activate enables it, and svg-line-deactivate / svg-line-toggle disable it, restoring the native mode-line untouched.
5.1.2. Rich mode-line
Here's a more complicated mode-line configuration that demonstrates svg-line's feature scope. It defines two rows, three-way alignment, a masthead icon, a custom segment, a clickable button, dynamic theme colours, and active/inactive styling:
;; A custom segment is just a zero-argument function returning a string.
;; This one shows how far point sits through the buffer, as a percentage.
(defunmy/buffer-percent()(format " %d%%"(/ (* 100 (point))(max 1 (point-max)))))(svg-line-define 'my-mode-line
:target 'mode-line
:active #'mode-line-window-selected-p
:icon(lambda()(nerd-icons-icon-for-mode major-mode)):background(lambda()(face-background 'mode-line nil t)):foreground(lambda()(face-foreground 'default nil t)):content(lambda()(list
;; row 1 — three independently-aligned segments on one row
(list :left(list (buffer-name)):center(list (symbol-name major-mode)):right(list (format-time-string "%H:%M")));; row 2 — custom segment + position on the left, a button on the right
(cons (list #'my/buffer-percent (format-mode-line " %l:%c"))(list (svg-line-seg "save":id 'ml-save
:help"buffer actions":action #'save-buffer
:action-help"save":menu '(("Revert" . revert-buffer)("Kill" . kill-current-buffer))))))))(svg-line-activate 'my-mode-line)
Line by line:
my/buffer-percent — any zero-argument function can be a segment; this one returns a string.
:active #'mode-line-window-selected-p — a predicate; when it's false (an unfocused window) the engine applies the :inactive-* colours instead.
:icon — a full-height "masthead" glyph drawn once on the left edge, spanning both rows. This is a function, so it tracks the current buffer's mode.
:background / :foreground — literal colours, or (as here) zero-argument functions evaluated on every render, so the bar follows your theme automatically.
row 1 — a :left/:center/:right plist puts three independently-aligned segments on a single row.
row 2 — a plain (LEFT . RIGHT) cons. Its left side mixes the custom function with an ordinary %l:%c string.
svg-line-seg — turns a segment into a button: left-click runs :action, right-click opens the :menu, and :help shows on hover in the echo area.
5.2. Tab-line
The tab-line is where the wrap layout is most useful: instead of scrolling overflow off the edge, it flows tabs onto subsequent rows.
:layout 'wrap — switches from rows of segments to a wrapping flow; overflowing tabs land on a new row rather than scrolling out of sight.
each item is (LABEL . STATE), where :current and :modified in the state plist drive the per-tab highlight and unsaved tint.
:current-background / :modified-foreground — the same value-or-function styling as the lines layout, just with current- and modified-tab variants.
6. Acknowledgement
Credit where it's due: this started as an experiment off Nicolas Rougier's work. His SVG explorations and that dual-header gist demonstrated that this was possible, and showed me how well this approach works.
JTR over at The Art Of Not Asking Why describes a problem—and its resolution—that I didn’t know existed. The TL;DR is that photographs taken with an iPhone are always captured in landscape mode but Apple’s software detects portrait photos and corrects the orientation on the fly.
The fix is pretty easy. He uses the mogrify tool of ImageMagick to auto-orient the photos based on their EXIF data. Since he’s viewing these photos in Org mode he wants an easy way of making the conversion from within Emacs. That’s a perfect job for Álvaro Ramírez’s dwim-shell-command, which JTR uses.
Take a look at the code and see how simple it is. Even if you aren’t an Elisp expert, it’s easy to do things like this with dwim-shell-command right from Emacs.
Org-mode has a capture system. You can be in any file in Emacs and invoke the capture system. Press a few keys and add text to a org heading in any file that you have set up a capture for.
It is easy to set it up. Firstly you assign a keyboard command to the capture system. In my case,
:bind ("C-c c" . org-capture)
Org-capture
You get this.
Journal Entry
You press a key. Let’s say you want to add a journal entry. Press j and get this.
Type what you want to say in the buffer and when done, press ⌃C ⌃C. This saves the additions to the journal and closes the buffer. Leaving you in the buffer you were in before you invoked the capture function.
This is the code-snippet which does the heavy lifting. "* %<%R: >\n%? \n"
The explanation:
*: Creates a level-1 heading.
%<%R: >: This is a time format code. It inserts the current time in 24-hour format (e.g., 21:45: ).
\n: Inserts a line break (a new line).
%?: This is where your flashing cursor will start, you can begin typing your journal entry without having to move the cursor yourself.
If you set up a capture system, you can easily add content to files without having to open them.
It is one of the useful features of Org-mode.
Tweaking the Capture System for Bookmarks
I paid for lifetime access for pinboard.in. But I get the feeling that this project is on maintenance mode and the developer has moved on. It still works but I want to stop relying on it and move my archived bookmarks to a plain-text Org file. I started a bookmarks.org file with this structure:
The capture would put the entries under the Bookmark header and I would refile the URL’s into appropriate sections periodically. Worked for a while. I learned more about capture templates and realized that I could lessen my work by filing the URL’s into their appropriate sections at the time of capture.
Org-capture
I didn’t like that. I wanted to be able to file the URL under it’s relevant heading when I captured it Now when I invoke capture I get this.
Bookmark Choices
Press b and I get this.
I can press the relevant key for the section I want and then paste in the URL. It gets inserted to the appropriate section.
Makes it easy.
This is an excerpt from the relevant section in my init.el.
This feature is one of the many that makes me love Org-mode.
Tweaking Org-mode
I am used to outlining programs. I have been using them for a long time. There is muscle memory build up over the years and I wanted to bring those into Org-mode. I am sure that the OG’s of Emacs are used to the Org-mode keybindings but I wanted to feel more comfortable using it. That comfort would increase if I used the keybindings I am used to.
New Org Header Outside/Inside
I wanted the new heading either to be a sub-heading within the current heading which conceptually is a daughter to me. Or the heading to be on the same level as the current heading I am under, conceptually a sibling. The third alternative, the new heading would be mom. That is a heading level higher than the one I was on. I wanted to be able to press a keyboard command and be at the start of the text of the new heading, mom, sibling or daughter. This piece of code does that:
(defun my/get-org-level-at-point ()
"Find the level of the headline the cursor is currently inside of by searching backward."
(save-excursion
(beginning-of-line)
;; 1. Check if the CURRENT line is a headline
(if (looking-at "^\\*+")
(length (match-string 0))
;; 2. If not, search backward for the nearest headline
(if (re-search-backward "^\\*+" (point-min) t)
(length (match-string 0))
0))))
(defun my/org-insert-child-headline ()
"Insert a new headline that is a child (Level + 1) at the end of the current subtree."
(interactive)
(let ((level (my/get-org-level-at-point)))
(if (> level 0)
(progn
(org-end-of-subtree)
(newline)
(insert (make-string (+ level 1) ?*) " "))
(user-error "Not inside an Org headline"))))
(defun my/org-insert-sibling-headline ()
"Insert a new headline at the same level at the end of the current subtree."
(interactive)
(let ((level (my/get-org-level-at-point)))
(if (> level 0)
(progn
(org-end-of-subtree)
(newline)
(insert (make-string level ?*) " "))
(user-error "Not inside an Org headline"))))
(defun my/org-insert-promoted-headline ()
"Insert a new headline one level higher (Level - 1) at the end of the current subtree."
(interactive)
(let ((level (my/get-org-level-at-point)))
(if (> level 0)
(let ((new-level (max 1 (- level 1))))
(org-end-of-subtree)
(newline)
(insert (make-string new-level ?*) " "))
(user-error "Not inside an Org headline"))))
Tweaking Some More
I am fond of the keybinding M-<right> and M-<left> as navigation keys in Emacs. In Org-mode it is bound to org-metaright and org-metaleft. That didn’t sound good to me. I was used to C-s-<right> and C-s-<left> for this function. Similarly M-<up> and M-<down> didn’t make sense to me. Too many years of using C-s-<up> and C-s-<down> for this function. So I changed them.
And I added keybindings for the functions I talk about in the previous section.
I needed to replace a page in a PDF with another PDF. This was a bit
of an annoying process on my iPad involving copying and pasting pages
in Noteful and then re-exporting them as a PDF, but it was easy to do
in Emacs thanks to pdf-tools and PDFtk.
;;;###autoload
(defunsacha-pdf-view-replace-current-page-with-file (file)
"Replace the current page in PDF View with FILE.Requires pdftk."
(interactive"FFile to insert: ")
(let ((temp-file (concat (make-temp-name "pdf-view") ".pdf")))
(call-process
"pdftk"
nil nil nil
(concat "A=" (expand-file-name (buffer-file-name)))
(concat "B=" (expand-file-name file))
"cat"
(format "A%d-%d"
1
(1- (pdf-view-current-page)))
"B"
(format "A%d-end"
(1+ (pdf-view-current-page)))
"output"
temp-file)
(rename-file temp-file (buffer-file-name) t)))
Sebastián Monía1 offered some alternatives to
the exeln function that I posted on June
4.2
First, he pointed out that there's no need to
bind asynch with the let function. Instead he
suggested that I use (when arg "&") to append the
ampersand when there's a prefix argument.
Thus, shell-command can be called this way:
Second, call async-shell-command rather
than shell-command with the "&" as suggested
in shell-command's doc string, which says, "You can
also use async-shell-command that automatically adds
'&'."3
Third, use thing-at-point from the built-in
thingatpt.el library to return the line at point rather
than calling buffer-substring.
(defunexeln (arg)
"Execute current line as a shell command.With prefix ARG, run asynchronously."
(interactive"P")
(funcall (if arg
#'async-shell-command
#'shell-command)
(thing-at-point 'line t)))
And although he didn't mention it explicitly, he reworded the doc
string -- it blends in seamlessly with the native functions' doc strings.
I set out to contribute to the Emacs community, but I'm getting so
much more out of it than I expected! Thank you again, Sebastián Monía!
Sean Whitton writes to tell us that the first Emacs 31 pretest, emacs.31.0.90, is available for download. It’s been almost two years since the first Emacs 30 pretest came out so we’re pretty much on schedule for our yearly major release.
As always, Irreal wants to give a huge shout out of thanks to all the developers who work so hard to keep the Emacs development bandwagon rolling. They do all this for free so we each owe them a word of thanks and, as I always say, the drinks are on us if we find ourselves in the same bar as one of them.
Whitton’s post has all the details concerning downloading and verifying the latest tarball. If you don’t mind living on the edge, give it a try and report any problems.
A few weeks ago I was on vacation. Of course I brought back quite a few pictures with me. When I got back, I sat to select some of them to make a gallery for my family and friends. I started with copying all pictures from two mobile phones and a camera to my laptop. Then I wanted to copy a few carefully chosen images to one directory. To my surprise, Emacs’ Image mode does not have a command to copy the currently viewed image to another directory.
Spam is an eternal problem, and while SpamAssassin is pretty good (I get around 700 mails per day, of which 670 are rejected as spam), there’s still some stuff that persistently gets through. A goodly portion of that is traditional random spam from random accounts, and there’s not much to be done about that, but there’s a recent trend of legitimate-looking things coming from persistent accounts — like BackerHome and BackerHive.
I’m guessing that eventually these will get so bad reputations that they end up on RBLs and will disappear into the mists, but meanwhile… I just thought that there should be a mechanism in Gnus to split these message to the spam group — without having to do much work.
Tada!
It’s a small package, and you can find it on Microsoft Github. It’s basically a tiny minor mode that adds a couple of commands, so you just hit z, check the entry (or not) and then C-c C-c.
(There’s also a command to edit the split data if things go off the rails, or just because you want to.)
B t to check the split trace, as normal.
So there you go. May your inboxes be slightly less spammy.
(And it’s fun doing some Gnus work again for the first time in years… I’ve forgotten what all the functions are called, though, so I had to use Claude to remind me. *gulp*)
The following exeln function passes the current line to the system
shell, which executes it, thus EXEcuting LiNe.
On Windows x86, my GNU Emacs has shell-file-name set to
cmdproxy.exe, which is provided by x86_64-w64-mingw32, with which
Emacs was compiled.
shell is invoked synchronously by default; a prefix argument can
change this to asynchronous.
In the video below, point is on a line of text that would print the
contents of hello_whirled.txt when entered at the Windows command
prompt (or DOS prompt). I press C-c x, which is bound
to exeln. The command is executed and the output is shown in *Shell
Command Output*, the default buffer used for synchronous output from
shell-command.
(defunexeln (arg)
"Execute the current line as a shell command.With prefix arg, operate asynchronously, same as calling(shell-command COMMAND) where COMMAND ends in '&'.Otherwise, execute synchronously."
(interactive"P")
(let (asynch)
(if arg
(setq asynch "&"))
(shell-command (concat
(buffer-substring
(line-beginning-position) (line-end-position))
asynch))))
“No-code automation” has been in Emacs far longer than its usage as a term of art. Better known as keyboard macros, this feature has allowed Emacs users to achieve their bespoke needs for decades, all without needing to know a whit about Lisp. I can testify to this personally: though I’ve been using Emacs since the early 90’s, only in the past three years has writing Elisp played any part in it. For most of my Emacs journey, I got by with just making keyboard macros.
If you’re unfamiliar with them, here are two links you should get to know:
My addition to the knowledge of those posts is to boost this fact: mouse events can also be captured by a keyboard macro. If you know where a command is in a menu, you can also record clicking on it. I think the ability to combine both keyboard and mouse events in a keyboard macro is compelling, so much so that I decided to emphasize this in Anju.
The recent Anju v1.5.0 release added the menu “Tools › Macro Recorder” to the menu bar as shown below.
With this, mouse enthusiasts can create and run keyboard macros without need to recall keybindings or deal with inconsistent command naming, as observed in Petersen’s post.
One thing that I TILed about keyboard macros in building this menu was the command list-keyboard-macros (see (emacs) Kmacro menu). This command is available in the “Macro Recorder” menu as the item “List macros”. This lets you manage multiple keyboard macros that have been defined during a session.
James Cherti has a new version (Release 1.0.4) of his inhibit-mouse package available. As the name suggests, it disables the mouse while you’re using Emacs. I’ve written about inhibit-mouse before. As I said in my previous post my first thought was that I don’t need this because I’ve already trained myself not to use the mouse while I’m in Emacs.
The thing is, though, that I mainly use my laptop—a MacBook Pro—which has a trackpad for mouse operations. Since I often use my laptop on my lap while sitting on the couch, it’s easy to inadvertently touch the trackpad with my palm and change focus from one window to another. Turning off the mouse would eliminate that from happening. Still, I do use my trackpad to scroll Web pages and emails that are displayed with WebKit because there’s no other decent way of doing so. Happily, inhibit-mouse is very configurable and you can, in particular, disable it’s use in any major modes you like. That may solve my WebKit problem.
Inhibit-mouse is a reimagining of Steve Purcell’s disable-mouse package. Cherti claims inhibit-mouse has some advantages—such as being more efficient—over disable-mouse. Take a look at the repository to see what they are.
If you’re looking for a way to banish the mouse from your Emacs experience, this seems like a good way of doing so. You can even leave a couple of escape hatches if you need to.
Ben Zanin (@gnomon@mastodon.social) - Mastodon: Robertson screwdriver owner, believer in the value of personal-scale computing and skeptic of the value of computing scales any larger than that
Sacha: I forgot to ask you how your lastname is pronounced.Ben: Oh, Zanin.Sacha: This is Emacs chat number 25 and here I am withBen Zanin.You have a math background and now you're in IT.Where did you encounter Emacs in the journey?Ben: So the reason I have a mathbackground is that I wanted to get intoprogramming language design and at the time sothat led me over to lambda calculus and that kindof thing and at the time it was at the time I wasgetting into university in like 2005-2006It was impossible to get into the computer programs,but I could get into math.I figured that would move me in the direction that I wantedto go in, so I did.Got to third year, and then every professorwho taught any of the courses I cared aboutall left the faculty at the same time.Sacha: Oh no!Ben: Yeah. Anyhow, that's a different story.But yeah, I got into Emacs because in the processof learning about Lambda Calculus, the Lispweenies found me.And yeah, I spent a bunch of time learning aboutthat.And it wasn't until like 10 years after I gotinto Common Lisp and Scheme that I actually gotinto Emacs at all.Sacha: That's interesting.Usually people, like, if they're doing Lispythings, they get into Emacs right away becauseLisp.But okay, so 10 years after.You're already well-used to parentheses at that point.Ben: Yes.But I guess it wasn't until about ten years ago,like around 2015 or so,that I started really getting into Emacs.I would still consider myself to be a beginner on that front.Sacha: Oh yeah? So what got you to get into it more?Ben: I found that I was looking for more structureddata management processes.Basically, I was looking for personal informationmanagement.And I kept bouncing off Emacs because I wanted toget into those tasks, but Emacs was such a richlearning process that I kept getting sidetracked,so I kept bouncing off of it.
2:19Ben got into Emacs because of twittering-mode
Ben: But I have to admit that one of the things thatoriginally actually got me into Emacs wastwittering mode.Oh yeah?Because I was looking for a tool that would letme, we'll probably get into this later in thechat, but I was looking for a tool that would letme keep a larger window of context about theconversations that I've been in.The Twitter apps and the Twitter websiteimplemented a really narrow window.I wanted to be able to search back a coupleof weeks for stuff that I had seen or talkedabout previously.Twittering-mode gave me the ability to keepdays or weeks of context in a single bufferthat I could then immediately search.So I didn't actually get into Emacs as a text editor,I got into it as an application platform,and then gradually learned the rest of it.This is actually fantastic. So I kind of stuck around after that.Sacha: That is the first time I've heard of someonecoming to Emacs because of Twitter.Ben: No, it's deeply embarrassing.Sacha: No, it's wonderful.I love that there's just so manyreasons why people come and the fact that youcould find something that would let you takethose notes and see that context and reply to it,and even, as I see in your config, work aroundslow keyboard response issues.Ben: And also the fact that that's stillin the config despite Twitter itself...I think I abandoned it in 2017, but it takes me alittle while to rip things out of my config.Sacha: Yeah, I see you're a lot moreactive in Mastodon these days. I see yourMonsterdon posts scrolled by my feed every so often.Yeah, so we dove right into that because a lotof the stuff in your config is interesting andyour workflows too.My idea for these Emacs chats is toshow people the kind of stuff that isn'timmediately obvious to newbies when they'relooking at someone's config.Because a lot of the stuff is new workflows andhow the keyboard shortcuts work together and howthis stuff fits into your life.That's not immediately obvious from the code.I've taken a look at your config, but beforewe jump into the gazillion things I wanted to askyou about, are there things that you particularlylove about your Emacs workflow?
4:30Emacs as a media playback platform with Versuri and Mpdel
Ben: I'm probably going to geta little bit of deserved flak for this, but Iuse Emacs a lot as a media playback platform.I spend a lot of time using Emacs to listen tomusic through MPV.And I've got some integration with Versuri, whichlets me...I think you've seen those customizationswhere what I've done is I've kind of duct-tapedthe two together.Versuri is an Emacs package for being able toquickly search through lyrics for songs.What I've done is I've bound Versuri to thepoint whereI've pulled up a page of lyrics, I now have ahotkey that bounces me over to a search of my MPDlibrary for where that song is, and vice versa.I've got MPD rigged up so that when I've got asong currently playing, I can bounce intoVerisuri to display the lyrics for thatparticular song.Something you probably have not seen in my configyet because I haven't finished it yet...What I'm working on is actually integratingOrg Mode with MPD, because I'd really like to be able tostreamline my process where occasionally when I'mlistening to something, I'll take notes eitherabout the lyrics or about the song. I'd liketo be able to link from Org Mode directly toeither that song, that album, or that particulartimecode.I don't have that yet, but I'm working on it.I think I'll probably lean on it quite a bit onceI have it.Sacha: Yeah, yeah.I saw your tweet from May, I think, where you'retalking about coming up with thisway of taking notes.think if you come up with maybe a customOrg Mode link type that can store the annotationand then let you go to it, I think that would bereally interesting.Especially if you figure out, okay, like, are youtaking notes in the album?Are you taking notes on the song?Are you taking notes on this moment in the song?That could all be very cool.Ben: Actually, do you mind if I share my screen?Sacha: Please.Ben: So one of the things I wanted tokind of note was... Let me... Oh yeah, this isactually going to be further embarrassing.I'm a terminal Emacs user.Sacha: I saw.Can you increase the font size, though?Ben: Absolutely, yeah.Sacha: Resizing your terminal so it's smallermakes everything look bigger...Ben: Is that better?Sacha: More.Some of us are older.Thank you.Ben: One of the things that's kind of unusual aboutmy MPD configuration is I've got a satellite config.Sorry, the line wrap is a little bit off here.What this means is that I have...the household file server maintains the MPDlibrary, but I've got multiple playback nodesaround the house. What that lets me do is...Sacha: You can play stuff on this...Ben: So what this means is that I'm controlling the...well, in this case, that's a littleMeLE Quieter3C that I've got in the living roomthat's kind of like thethe home media server, the home playback machine.Fundamentally, I'm an ops guy, I'm a sys admin,and I've got, unfortunately, a fleet of machines around the house.What this lets me do is easily control eachone of them.Instead of each one maintaining its ownlibrary of music files, the file server itselfindexes them, which means that library updatesare almost instantaneous, instead of having toread over the network to pull metadata out ofeach individual file.So having a satellite setup lets me...The real benefit is that MPD tracks albums,directories, and files as URLs.That means that I have a single globalnamespace of URLs for all of the media that'scurrently in the library, which means that I canannotate from any machine, but have it mean one thing.It makes it convenient for navigation, but italso makes it convenient for keeping notes, whichI'm currently doing manually and working on thoseOrg link types to be able to make it a little bitmore smooth than it currently is.Sacha: So you've got your central store of music files.You've got URLs for them so you can talk about them.That's just one identifier per song.You've got multiple speakers that you can useyour completing interface to say, okay, I want toplay this over there.You have Emacs controlling all of that.
9:13Emacs on Android with Termux
Sacha: Now, is that Emacs on your laptop and you justtake it around and you say, okay, I'm going tosit in the living room for a little bit orwhatever and play there.Or do you... Ah, there you go.That's what I was going to ask.All right.So Emacs on your phone.The Android port or Termux?Ben: I have both installed.I think you actually saw this a few monthsago when I was running performance comparisonsbetween the Termux version of Emacs and thenative port, and found that the native portgenerally ran anything CPU-intensiveroughly twice as fast.But I still use the Termux version because it's...I'm not sure if you played around with theAndroid terminal virtualization layer at all, butit's not great.I really appreciate the integration thatTermux gives me with Android features.For example, being able to query the sensors,such as GPS or temperature sensors, and I canactually pull those in from the Emacs side.And that's something I kind of want to get into.Sacha: What do you think of using thetemperature sensors for?What can Emacs do with that?Ben: It's not so much the fact that Iuse the temperature sensors as that when I pullthe sensors, that's the most remarkable valuethat I get out of it.But one of the interesting things is thebarometric pressure sensor, which gives meheight, which matters because when I'm out andabout and if I stop to record an entry in myjournal, for example, I'll just pull the sensorsand dump them into the header in the entry that I'm writing.The barometric sensor, I'll get the GPS, sothat'll tell me what the actual height is at thatlocation on the earth. The barometric sensoralso gives me a little bit of insight into the weather.So it's not so much the temperature sensoris what my temperature is, but just like ifit's a hot day or not.Sacha: I am very curious about that setup.So if you happen to share your, I don't know, Orgcapture for Termux that includes all these things...You don't have to show me the actual stuff, butyou know, at some point I think other people willbe curious about what kind of benefits they canget from running Emacs on their phones.Ben: So, I mean, I guess I'll...One of the benefits that I get is the ability tokeep shopping.So I'm a little bit of a militant cyclist.One of the things that I often do is leaveBen: notes about things that I need to take care of inparticular areas of the city.The nice thing is that I can just drop themdirectly in commits right as I'm going.So I often have a long list of updates that arefrom Emacs on my phone, just because it's convenient.All right.There we go for Monsterdon, in fact.Sacha: Nice, nice.Then that'sSyncthing or whatever else to just get it copied backto your laptop or just on your phone?Ben: Straight Magit mode.Sacha: Oh, yeah?Ben: That's one of the things that Ifound was a little bit clunkier when I wasrunning virtualized Emacs under the Androidemulator and also the native Android port ofEmacs.They are a little bit more troublesome to getMagit to work.Because I rely on that for syncing back andforth from my phone,that's one of the reasons why I stuck with Termux.Sacha: Very cool, very cool.I like Termux's little bar of extrakeyboard keys that you can have, so you can havea regular keyboard and then you can just haveyour Controls and your Alts and whatever on thatlittle extra bar.Termux is quite interesting.Ben: I think I'm probably pushing itharder than it is meant to be pushed.Sacha: That's the fun of it.I don't exactly know how everything will shakeout, but probably with Google trying to lock downthe developer ecosystemin a few months, right?They're saying, oh, you know, it's got to be ADBin order to get these unsigned apps on.We'll have to see how it all shakes out.But I'm hoping Termux can survive because I likethat one too.Ben: Yeah, me too.Sacha: Okay, so you've got interestingmusic, an interesting music setup with lyrics andplayback and all that stuff.You've got your phone, which also runs Emacs andfrom which you can, you've also set it up so youcan control your music from your phone?Ben: Yes.Sacha: Okay.
13:44Keyboards and other devices
Sacha: When I was reading through your toots, I noticedyou like to play around with other keyboards andother devices like the 8BitDo.Do you have any of that talking to Emacs too?Ben: [Keychron B11 Pro is] the keyboard I'm currently using.I got this so I could keep it in my purse andjust like walk around with it, but it turns outit's super comfortable and I'm accidentally usingit as a daily driver.Sacha: All right.Name-drop the keyboard for all the people wholike the device recommendations.Ben: It's a Keychron B11 Pro.It runs ZMK.ZMK, I suppose.And if you've seen me interacting withPete Johanson on Mastodon, he's the lead developer ofthat firmware package.It's a little bit like QMK, except thatfundamentally QMK is a polling architecture, andit works really well for very restrictedmicrocontrollers.ZMK is interrupt-based, which means it istremendously more efficient in terms of power draw.So if you want a Bluetooth keyboard, you shouldprobably run ZMK on it.Anyhow, yeah, it's fantastic.And I do have a bit of a keyboard problem where Itend to...Sacha: Many Emacs people have keyboard problems.Ben: Right? I feel like I'm in good company right now.Sacha: Yeah, yeah, yeah.So, devices, yep, gotcha.And this has become your main keyboard even forregular computing?Ben: In the last couple of weeks, yeah.It's super comfortable.Because it's so flat, I can get away withouthaving to use palm rests to actually keep in adecent posture,because of the curvature of it..Like, it's an Alice layout.The key travel isn't too bad.It's actually quite comfortable.I found that I needed a little bit ofacclimatization to get used to split keyboards.This one has roughly the spread of a split,but it seems to be easier for my muscle memory.So yeah, I didn't intend to leave it on my desk,but it stuck and has kind of stayed there for now.Sacha: Does it have any special ergonomicsfor all the modifiers that we like to do?Or do you just use Caps as Control or whatever else?Ben: Actually, I don't use Caps asControl and I actually really need to get intoremapping that.ZMK has a very rich remapping story, as I expectyou to imagine, from a custom firmware.The macros are intense, and you can getreally deep in customization.I have done none of that on this keyboardyet, because it's only, I think, a couple ofmonths old at this point.Sacha: You've been settling in.As you said, this has been yourmain keyboard for a little while.Charlie Baker says, "yeah, I love the split keyboard.Recently bought one myself.I was getting so much neck pain, you know,shoulder and neck pain from so many hours keepinghands close together."But the split lets his shoulders relax.So probably you're getting the same, like, ha, my arms.
16:44Benefits of a split keyboard
Ben: The two things that I first noticedwhen I moved to a split keyboard was one, mywrists started feeling a lot nicer and two, I wasimmediately able to bench press like 20 poundsmore the next week.It was amazing how much of a difference it madeand it showed up in the data.Sacha: Wow.There was a weightlifting talk at EmacsConf last year, I think.So there's a surprising overlap between thepeople who are checking their weightlifting statsand the people who are into Emacs.Naturally, with Org Mode.There you go.Ben: Let's not look at those numbers too closely.I'm not too proud of a bunch of them.But yes, I find that Org capture templates let mekeep on top of that and not really think aboutit, which is great because you don't want tothink about it.You want to gather the data and think about itseparately so that you canstay emotionally divested from what the numbers mean.Sacha: I know.I'm totally happy to dig into the Org capture,especially if you do any graphing.People always love graphing their progress, right?But if you're like, I don't really want to showmy numbers at the moment, that is alsounderstandable and okay.Ben: I don't, I'm afraid. Sorry.Sacha: That's okay.Ben: It took me a couple years to getused to being on camera at all.I don't really like my appearance very much.I'm working on that, as you can see.I've had to work on that to be able to work remotely.It's a work in progress.I'm getting through it.Sacha: You know us. We're very much focused on text.In fact, you even use Emacs in the terminal.That's very text-y.
18:22Meeting workflow
Sacha: One of the interesting things actually that Iwanted to ask you about since you mentionedmeetings is you probably also have the role ofdesignated note-taker.You mentioned in one of your toots that you takenotes and people are like, what are you doing that in?How are you taking your notes?And it's Emacs.Ben: Yes, so actually that's one of thethings I should lead off with as an apology.I probably won't be able to sharemany of my capture templates because I don't usethem in my personal life very much.They're mostly on my work machine. I'vegot capture templates for impromptu meetingswhere it's just like an exploratory, we have aproblem we need to solve, we're kind of talkingthrough a discussion,a separate capture template for meetings withagendas to make sure that we stay on them andthat we log decisions,and a separate set of templates for... So I havea team of direct reports and they each havedifferent cares and different topics that we'reworking to develop in their professional careers.I find that it's really useful to be able tokeep some continuity between our conversations.It also makes it very easy to export thatentire dataset, share it with them to make surethat they can consult it at the same time.If I got anything wrong, I can fold theircorrections in.But all of those templates, unfortunately, are onmy work machine.Sacha: We'll just sketch out the generalidea in abstract details and then people who wantto implement it for themselves can fill in the blanks.For example, when you're having a meeting withyour direct reports, are the tasks related tothem in an Org agenda?Are you using dynamic blocks?Is it tracked somewhere else or is it in Org?Ben: It's straight in Org mode.So most of the touch points that we have are moreabout professional development and their caresand concerns, rather than specific deliverables.Usually deliverables we manage at a team level.But if there are specific things that individualsare working on, they will be in to-dos undertheir subheadings in a way that show up on theagenda if we have assigned deadlines for them.But generally, if there's a deadline on a task,it's becauseI'm doing something and they need to track it, orthey're doing something and I need to track it.If I'm the only guy using Emacs, then OrgMode won't work for that,so there aren't a lot of those.But if it's just something that I need to checkup on to make sure thatsomething that... Like they've got planned leave forexample, or they have a cousin's wedding thatthey need to go off to, or something that I justneed to keep in my brain that's not necessarilydeliverable, then it would beappropriate to keep that in a place where it'llonly show up on my agenda.So that's the kind of decision making that Iapply there.
21:11Narrowing
Sacha: And you mentioned you have asubheading, I guess a subheading per person orsort of... Or do you use tags to keep trackof something that might touch several people?Ben: Usually a section per person, andthat's more of a convenience than anything else.That lets me narrow to just that subheading andshare my screen during the meetings.Then I don't have to worry about accidentallyleaking anybody else's information into thescreen share or anything like that.Obviously we let off with conversations aboutthem being all right with that.But the ability to very clearly and simplydelineate"This domain of my notes pertains to this person"and being able to be confident and share thatconfidence that there will be no leakage meansthat we can explore topics and talk about them ina way that might otherwise be a little bit morerestrictive.So being able to do that simply, and being able toestablish a very clear delineation around whoseinformation belongs where and where it should beshared turns out to be pretty valuable.Sacha: Yeah, and that's a technique Ithink that especially people who are new to Emacsand who aren't used to narrowing and wideningmight not know how to use effectively.I think narrow is even one of the commands that'sdisabled by default.You've got to say, yeah, you know, I'm not scared.I know what to do.Ben: Yeah, it's kind of bizarre to methat it is, but yeah.Sacha: I can imagine people accidentallytriggering it and they're like, oh no, the restof my file is missing.But if you know how to narrow to a region, andOrg even has those commands to easily narrow to a subtree...I think it's even part of the default speedcommand so you can trigger it right from a heading.But it's great for that kind of restriction.
22:58There's even an internal Slack channel about Emacs at Ben's company
Sacha: Okay, so the reason why I was asking about thatis because some people are working with peoplewho are not using Emacs, so it's very interestingto see what the kinds of... It's very rare forpeople to work with other people who actuallyuse... Are there any other Emacs people in yourcompany, for example?Ben: There's an entire Emacs Slack topicabout that, yeah.It's kind of great.Sacha: What is that like to have co-workers who do Emacs?Because this is a rare experience.Ben: It's super cool.It's also neat to see the very, very differentways that people use it.But yeah, oftentimes people will talk aboutproblems that they have with particular internaltools, and somebody's like, oh yeah, go check outthis repo on GitLab that I published last weekwhere I got sick of it and decided to solve thatproblem categorically.It's actually super cool.And some of the folks at...Generally, I tried not to mention my currentemployer at any point.Obviously, it's not secret.It's in the init file.But yeah, I don't tend to get into that deeply.But some of the other people who work at mycompany, they maintain venerable Emacs packages.So it's awesome to be able to go and talk withsome of the folks whoI've been working on the code that I've beenusing for a decade and we are now coworkers.It's lovely.Sacha: Oh, that's so nice.I'm glad you have that kind of little communityin there.Ben: Yeah. Bunch of nerds.Sacha: So I suspect some people will be looking up yourcompany after this.I think it's also mentioned in LinkedIn and sortof like, okay, let's see if there's any jobopenings.Ben: If it's mentioned on LinkedIn, thatis somebody else.I haven't logged into LinkedIn in 15 years and Inever will.
24:50Ben keeps Org capture templates as individual files and adapts them to different meeting flows
Sacha: We do have a question from Shae.Shae is asking, how do you make a capturetemplate to stay on agenda and record decisions?You got any tips for that?I'm guessing this is more of a human thing ratherthan an Org thing, but maybe you have some ideason how you keep something on track.Ben: So I'll actually push back on the"It's a human thing rather than an Org thing".I strongly believe that one of the real valuesof Org Mode is that it's a very plastic system.Fundamentally, I think that it is a human systembecause it allows you to express exactly thosekinds of trade-offs in a really, really fluid way.I love the personal information management thatPalm Pilots provided, for example,but it was pretty restrictive.One of the things that I love about Org Modeis that if you find that a particular person hasa particular conversation style, it's really easyto modify your Org Mode capture templates to beable to capture that particular flow that youhave with that person.Or with a particular group of a recurringmeeting, for example, that tends to flow in aparticular way.Super easy to update the templates that I use tocapture those particular meetings to make iteasier to match the general conversation flowwith the notes that I will be taking about it.Sacha: Wow, that sounds prettysophisticated.Ben: Well, I mean, that's the thing.It's not sophisticated.It tracks the human process very easily.So it's really lightweight.So you don't have to have a lot of sophisticationto make it very, very useful.You just have to have a feedback loop that youcan tune every time with one or two minutes of effort.And that's one of the reasons why I depend onMagit mode so much is that it lets me trackthose things.But yeah, to answer Shae's question about how doI track those particular things.So if it's a meeting where one of my direct reportshas a particular set of topics that wetend to investigate, like somebody who'sconcentrated on career growth.So we're talking about the areas in which we wantto see development.I'll absolutely update the capture templates forthat particular person to say, all right, here'swhat we talked about last time.Here are the things that were done between ourlast two conversations about how we move in that direction.Were they successful or not?Did it require a lot of effort?So was it something that more effort should beput into to be able to drive down the work over time,to be able to produce those results?But yeah, that goes into the templatesand that goes into the cadence of conversations that wetalked about in Capture.Sacha: So that's really interesting.You modify the capture templates with thenotes that you want to have easily available thenext time you chat with them.Ben: Exactly, yeah.Sacha: The capture templates are still defined as asetq somewhere in your thing, or are yougoing into the customized interface?Ben: So I actually keep the capture modetemplates as raw files that are referred to, andthat makes it easier to version them in a waythat like, I mean, sure, like my Emacs init file,if you look at the Git history of it, it has awhole bunch of different...Sacha: I had not considered having capturetemplates as files files.It worked out really well.Ben: So you can see that... It's a littlebit hard to see with the font this small, but youcan see that I've got a lot of changes to, forexample, my init file, but keeping them inindividual capture mode template files makes it alittle bit easier to just look at the history ofthat particular file and see why particularchanges were made.Sacha: I'm going to try that.I think that's a great idea because it allows youto be a lot more granular about the notes.
28:45Personal-scale software and the journey
Sacha: I saw in that very brief flash of your changelog message that you like to writefairly detailed commit messages that talk aboutwhy a change was made instead of just "a newfunction, new command,"very terse updates that I sometimes just try toget away with.Tell us more about that, because I think you'vehad a couple of toots about reading source codeand reading commits.Ben: Yeah.So I guess one of the things that I most appreciate aboutsoftware in general, and specifically personalsoftware, like personal-scale software that'sbeen written by an amount of people that youcould fit into a room to have a conversationabout it...One of the things that I most appreciate aboutthat is that almost all software written that wayis fundamentally a diary about the way that aperson learned how to solve a set of problemsthat they might not have known about when theydecided to at the beginning.It's this fascinating process oftracking somebody's voyage through the problemlandscape as they discover other people who havetouched on topics that are tangential to theproblem being solved by that software package.It's such a personal and fascinating experienceto see somebody go from "I know just enough abouta problem to be able to decide that I want tobuild a machine that works on it" to "I havethis deeper understanding of how the problemactually exists in the broader set of things thatpeople care about,oriented along the axis of what machinery cando to help solve parts of that problem."The commit logs for a program arelike a map through that territory.It's wonderful to read.It gives you a lot of insight into the persondoing the navigation.When you see 16 commits on December 24th of 2023,like, that person probably had a littlebit of time to work on it.Then, when you see a bunch of commits that are5 p.m. Monday to Friday, like, okay, this isprobably done in a particular way.It's this deeply personal process ofseeing how problems are learned about.I just really appreciate that.Sacha: I think what you're saying aboutpersonal-scale software and getting asense of people's journey as they learn tounderstand a problem and as they start toprototype a solution... Because you never quite comeacross the right solution the first time around.You're figuring things out,You're borrowing things from other people.I think that will resonate a lot with lots ofpeople in the Emacs community, because Emacs useis so personal, as you mentioned when you werelooking at the Slack channel.I was wondering, in your personal practice, asyou figure things out, what kinds of things help you?Is it mostly a matter of actually sitting downand taking the time to write the literateprogramming stuff around the code blocks or thecommit messages,or are there other tools or techniques that helpyou do that?Are there tools or techniques that help me writedown your journey along the way as you thinkabout the code?What's your practice?For example, when you come across something thatyou want to figure out, how do you go about doing it?Ben: So it depends on how I'mapproaching the project.One of the neat things about software is thatit's a document and a device at the same time.You can care about it because of the thingthat it does, or you can care about it because ofthe information that it captures.If I'm digging into a program because it doesa thing that I want to learn, then I'll payattention to the device aspect of it.That usually means that I'll start with itsown documentation.If it has a man page, I'll read that.If it has user docs, I'll read those.Usually, I'll start keeping notes inan Org Mode file, because it's easy to hyperlinkback to it and add my own annotations in parallel to theactual authoritative source.If I'm reading software primarily as a document,then I'll start by reading the source code andthe commit logs, usually the most recent ones,and then I'll jump back to the beginning of theproject and read upwards at the beginning, andthen fill in the blanks iteratively, if it's aproject that's small enough or has little enoughhistory that I can do that.Again, I'll usually start an Org Mode filespecific to that particular exploration that willlet me organize my notes as I go.I really do rely on the external brain that I cankeep in an Org Mode file.I tend to have a pretty decent long-term memory,but being able to bridge the gap betweenshort-term memory and long-term memory is super,super useful.Leaving myself hints that let me dredge thingsback out of long-term andreload it into the hot cache of short-term really,really helps out, because that lets me maintainthat flow state or get back into that flow state.When you've got like the whole program, all thecontext that you've absorbed up until now and theideas of the areas that you want toinvestigate,being able to hot-reload all of that and thenpick up where I left off is super useful.But the meat brain can't do it.I need the machine brain too.
34:07vc-git-grep for finding notes again
Sacha: Tell me about this dredging up process.Are you a lots of little files person?A couple of large files?A project file,there's an Org file in each project that you look up?How do you find things, especially if you don'tremember the exact words?Ben: So it's usually like an Org Modeper category, and they get consolidated.Let me shrink this down a little bit.So usually it's an Org Mode category per file.If there's something super specific, then usuallyit'll live out in its own place until Iget around to...Sacha: I love that you have an Org Filespecifically for Mug Cake.Ben: But that's the thing.It'll live off in its own thing until it getsintegrated into the list where the long-termstuff lives.I promise this is pertinent toyour actual question.Sacha: No, no, this is very pertinent.Ben: Usually, lots of littlefiles while I'm still working on something,and then as that something becomes part of my larger lifeand has links to other things,Ben: then it'll kind of get centralized into one of the Org Modefiles that has a broader topic purpose basically.Sacha: If it's very long-term and you can't rememberthe exact words to find something, how do you generally findfind your notes?Ben: That way.Sacha: You start grepping various keywords and try tofind it.Ben: Yeah.So one of the things that I don't yet have turnedon, and actually you inspired me to look intothis, was so... Actually, do we have enough time?Yeah, okay.I'm just looking at the clock.One of the things that I wanted to get into waslong-term searching and searchability.Yeah.So I use SQLite's indexing for a lot of things,and I really appreciate its porter stemmingbecause it lets you search for stemmed words,which are kind of approximate matches, which isuseful, but less useful than vector databases.You actually put a little bit of work intoindexing topics based on vector similarity.Sacha: Which I haven't gotten back to, soI'm glad to see you managed toexperiment with it,see what you come up with.Ben: I don't have anything to showyet, except that it's an interesting topic.Because I'm word-oriented, I will often rememberindividual keywords, or I'll have enough patiencethat I can sift through a list of potentialkeywords as I'm grepping for stuff.
36:55Add keywords to make things easier to find again
Ben: If I find that my first three or fourattempts at searching for a keyword don't findthe topic that I'm looking for, once I doeventually dig up the topic, I will add thosekeywords that I was searching for just so I canfind it next time, expecting that future me willprobably behave more or less like current me.But yeah, being able to use a vectordatabase to search for headings that includerelated topics instead of related words...I'd really like to get there.I'm not there yet,and I think that's going to be interesting and useful.I also think it's going to be challenging torepresent Org Mode's hierarchical structureto restrict the trainingof particular vector setsto be able to cast an increasingly wide netfor where I want the searches to run.I don't know how that's going to be solved yet,but I'm going to be looking into it.
37:47Keybindings and terminals; wezterm
Sacha: @PuercoPop has a question regardingterminal Emacs."Do you need to change any of the keybindings toavoid clashes with the terminal?"Some keybindings don't work onterminals, or some terminals already have thesekeybindings set.Ben: So I have good news and bad news there.The good news is that... One of the terminalsthat I'm using right now on most of my systems isWezterm.It's really good.I started off with [meant to say Kitty], and I kind of bouncedoff that project because of some of the behaviorof the lead developers.I won't get too deep into it, but what I found isthat Wezterm...It gives me very little friction that way.It doesn't have a lot of its own keybindings,and that's a relief.It means that I really don't have to... I don'tthink I've had to put any time into customizingWezterm to get out of the way of Emacs or Screen.I should mention, I am running Emacs withinScreen,so that introduces another layer.C-a a, for example, is
beginning-of-linefor me, even though C-a itself is thedefault Emacs keybinding.But yeah, I think that I ended up choosingterminal software specifically on that merit, sothat it doesn't get in the way.That's actually one of the things that Termux is...The default Google keyboard keeps stealing key bindings.It'll update, and all of a sudden, I can't use aparticular Alt key combination anymore, becausenow it invokes a Google keyboard shortcut forpulling things out of the Android clipboard, forexample, which is really kind of annoying.But yeah, in terms of terminals on full-fledgedmachines, I generally don't have that particularproblem.Except for... What was the name of it?It was... It was a zap-to on-the-screen packagethat alphapapa wrote, I believe, that I...Actually, let me just look it up.Yeah, Avy.Sacha: Oh yeah?Ben: So I wanted to start picking thisup in 2021, and yeah, control colon doesn't workin terminals.So the mode itself is fantastic, and when I'musing it in a GUI Emacs, it's very useful, and Irarely use it now specifically because of thatparticular terminal problem.That is self-inflicted.That is not a problem with the package.That is a me problem.But yeah, I think this is the notable one that Ibounced off of.Sacha: Yeah, just trying to find theright, you know, a key binding that will pass.Because you can't get used to key binding in onesystem and then not have it available in othersystems.It's just going to mess with your brain.So yeah, Ray points out, yeah, Google stealsControl Shift K, which he uses to kill tabs tothe right.So it's like, oh.Ben: Infuriating.Sacha: Yeah, yeah.And of course, none of the standard keyboardshave a super key on the thing, so you can't justtack on another modifier that'll get through.Ben: That's actually one of the reasonsthat I picked up this particular keyboard isBrian Carlson.Another Torontonian.He works on Git LFS and some other stuff.He was specifically looking for a keyboard thathad a super key that he could remap.So four keys to the right of space, which thisone has.And because it's ZMK, it's remappable.I think this might be suitable for his purpose,except that he wants a QMK keyboard, specificallybecause the development tools for QMK arepackaged in W, and that's a plus for him.Anyhow, yes, I agree.Like, not having a super and a hyper key on akeyboardSacha: feels like like one of your fingersthat are cramped up we need more modifiers well Imean you know pipe organTell us about that.Ben: What is this?Oh yeah, foot pedals.Yeah, and I actually do have these wired into alittle Atmel microcontroller running QMK.I honestly tried the foot pedal thing for alittle while.It was hilarious.I did not find it useful.Sacha: I don't have the hand-eye-footcoordination to do that thing at the same time.Ben: Maybe if I had learned piano as akid, it would have been good.But yeah, I don't seem to be able to do it.But I gave it the old college try and it was fun.
42:38Timers: tea-timer, tmr
Sacha: Okay, I had a couple of things Iwanted to ask about in your config.You have two types of timers.You have tea-timer and you have Prot's TMR.Do you use them for different purposes?What's going on here?Ben: So I'm trying them out.I tried TTimer first because it was the first onethat I found, and it was useful.I was actually using it in meetings because Iwould, when I was trying to keep us on topic, Iwould use that to remind us that, oh, we've gotfour other topics we need to get through.We're trying to give this one five minutes.We're running up on four.And it was just because it was super low overhead.It was easy to pick up.It was easy to have it displayed on my screen.And it didn't feel like I was...Running a chess timer on everyone.It's very subtle in the mode line.It was useful.But what I found was that when I was...Running multiple timers simultaneously.TMR, just the fact that you can list all thetimers and manage them in a separate buffer.It's richer and I appreciated some of itsdocumentation more.I haven't fully switched over to it yet.I'm still in exploratory mode.In fact, this is probably like... So I actuallyhave a bunch more packages installed than I'mcurrently using.So I'm going to shrink this down a little bitjust so that it doesn't line wrap.
43:57Different stages of package use
Ben: But yeah, so I've got, I think about 140 packageslocally cloned.I've got, as you can see in my init,about half of that actually installed.There are various phases. I've got a clone, but I don'thave it in my init. Or I have it in my init, butthere's another package that offerssimilar functionality. Or I'm all-in on this particularchoice and I'm removing the other ones.It's a gradual kind of progression.Sacha: Yeah, we're all auditioningpackages to see if they fit in our workflow andall that stuff.I was curious also about your elfeed things.You have a few things related to elfeed.Actually, do you want to talk about the thing youjust highlighted first?Ben: No, we'll get back to it in a sec.I'm keeping an eye on the clock.Sacha: But yeah, elfeed.
44:47Elfeed
Sacha: Yeah, you've got a couple of interesting thingsin your elfeed setup, including picking a searchfrom a bookmark or other shortcuts like that.Ben: So I have discovered in myconversations with the new maintainers for elfeedthat my elfeed habits are very deviant.So let me actually start off by going through...You can see that like the top of my elfeed list iskind of in one format and down at the bottom, theones that are closer to present day are organizedin a different way.Sacha: You've got tags now.Ben: So my feed list is, I mean, itstarted in Google Reader.It's kind of been forward ported since then.It's long.Sacha: I love the comments.Ben: But one of the consequences ofhaving a long feed list is that I have anenormous elfeed database.And I use it for completely different purposes.So for example, I'm going to show off that littledefault search.I keep an eye on projects that have releasesthat aren't packaged by Debian, for example.So I've got this little ATS Mini.basically a small AM FM radio that happens to runon ESP32 and the firmware for this communitydeveloped and it's kind of interesting but likethat's not packaged by Debian so I pay attentionto or I subscribe to the release feed for thatparticular project.I do keep in keep an eye on the Linux kernelespecially these days becauseThe gallop of security vulnerabilities coming outof mythos analyses right now means that I have topay more attention than usual to fresh updates.So generally I run Debian stable, but I do runkernels from backports and I want to know whenthose are available.MeshTastic.I was paying more attention to this a couple ofweeks ago.I'm not going to reach that right now.But yeah, the local MeshTastic community inToronto is plagued by a couple of griefers thatmake it a lot less fun.So I'm paying a bit less attention to that rightnow.But yeah, so like one of the bookmarks that Ihave is software currency.Another one is, for example, the YouTube channelsthat I subscribe to.Thank goodness for Elf YouTube.It is so nice to be able to get the transcriptsfor things directly in there.Sacha: There's even a sponsor blockintegration so you can skip all the promotionsand stuff.Ben: Yeah, I mean, so again, my use ofYouTube is also deviant in that I pretty muchstrictly subscribe to RSS feeds and they'redownloaded onto the file server.So when a new recording comes out, it getsdropped there.I'll watch it.And then I've got a little widget that scansthrough my Kodi database for watched files.Once YouTube files show up in the watch list,they're automatically purged.And it means I just never see an ad.It's not just satisfying.I don't think that I would be able to payattention if I was being constantly interruptedbecause of the way that my brain works.But yeah, so being able to quickly search forYouTube is one thing.
48:36Spoilers
Ben: I do have articles that I've marked as spoilers for mediathat I haven't watched or read yet.Maybe I go to an extreme degree, but I'll try toavoid previews for new movies, for example.I do want to actually go back to them later on.Marking articles as having spoilers that I wantto revisit later on is an easy way of not havingto worry about it anymore.For a while, back in the days when I waspaying more attention to... Enter the Dragon wasthe sequel to... What was that TV show?George R.R. Martin... Seven seasons and it went badly off therails in season six.Sacha: Game of Thrones.Ben: Thank you.So when I was watching that for a while, severalof the sites that I was reading would haveindividual episode updates.I really appreciated having a list of Elfeed keywordsthat I could automatically apply those tags to.I wouldn't even see the headlines because itwas problematic enough.I've become less...Sacha: Nice.Ben: I've been putting less effort intomaintaining that now, but the infrastructure isstill there, and I can lean on it if I need to.
49:53Comparing different news sources
Ben: One of the things that I don't have set up right nowis a quick search for the municipal topics that I cover.I tend to subscribe to a lot of news because Ifound that, for example, it's interesting to seehow the Toronto Star covers stuff differentlyfrom other local newspapers.It's useful to be able to quickly pull upthe five or six publications that covernews in the same way and then look through theannotations for them or add the annotationsmyself. I can see that this particular storywas covered by this journalist in thispublication in this way, and then it lets mecross-reference so that I can pay attention totopics that are under-covered or publicationsthat habitually leave out particular aspects ofnews stories.It lets me pay more attention tothe trends of publications as well as to thestories that they're covering.The consequence of that is that my Elfeeddatabase is 4.5 gigs.It's common for me... I don't know ifthat actually shows.It's common for me to have like 65,000 articlesin like the six month horizon for the default Elfeedsearches.That means that searches and redraws areexpensive, even on a relatively performant machine.You've probably seen some of the workaroundsthat I've got.This little bookmark selector is one of thoseworkarounds.Elfeed's interactive search: super, super useful.But if you're trying to do it like this...Actually, it's not so bad.Sacha: I love this.When you see someone using Elfeed for 65,000items, you get a sense of what it can be usedfor when you're really stressing it.Ben: And the organization of the bookmarks that I havemeans that I do have one river of newsof all of the things that I want to pay attention to.But it's seven or eight pretty divergent topicswith not a lot of overlap.It's neat to be able tothink of Elfeed as the thing where newsinformation comes in. The individualbookmarks are the topics that are groupedtogether that I actually care about and want toread about in concert with each other.If I specifically narrow it down to just Emacsstuff, one of the things that I can easily do isadd a bookmark for that search. If I name it...Now that I've got that bookmark saved...Sacha: And then it's like, bookmark annotation.Ben: Right. It ends up in my dot file as a git commit.
53:13Bookmark naming conventions
Ben: Now that that bookmark exists, simply because ofthe naming (elfeed-search-...), now it shows up incompletion.Sacha: Precisely this sort of stuff.I am under-utilizing bookmarks, I think.
53:24Naming conventions simplify building new workflows
Sacha: I love this idea of using bookmarkswith a naming conventionand then writing Emacs Lispto take advantage of that naming conventionto make that easy to jump to, easy to use in other things.Ben: Yeah, it means I don't really have...When I notice that there's a thing I don't have,it diminishes the activation energy forbuilding a new workflow.It means that I don't have to put a lot ofthought into it.I can quickly do it.If it turns out to not be useful, I canquickly get rid of it.Sacha: Very cool.
53:50elfeed-curate for annotations
Sacha: I had one more thing that I wanted to ask youabout elfeed that I want to squeeze in,in the five minutes that I have before the kiddo comes outfor lunch break.This elfeed-curate that you're using, this is thefirst time I've come across it in the config.Are you sharing your notes or your selectionswith other people, or just for yourself?Ben: No. It's just for myself.What I'm trying to replicate is,back in Google Reader days,I really appreciated how when you added an annotationto an article that you were reading,by default, that annotation would be viewable byother people in your social graph.That was super interesting.Sometimes you could also add personal-only annotations.Actually, I don't think that's the keyword that it uses.I think it’s just +ann.Sacha: Also, because you have an Emacskeyword on it, so I don't know whether you haveany annotated Emacs ones.Ben: Yeah.Well, I mean, generally, if I've added anannotation, it will be.So, for example, here.Right? Super useful.Well, super useful for me, anyhow.If I find that there's an annotation that is more...This is inflammatory.It doesn't need to go out on the web.Sacha: Sorry, did you need me to kill the stream?I have a 10-second window.Ben: No, it's all good.I'm not worried about sharing this, but it's notsomething I've posted.What the nice thing is, is that if it issomething that I want to share, it's really,really easy to just drop this into Mastodon mode.Sacha: Very cool.Ben: That's one of the ways that I use it.Because the annotations are just Org Modefiles, you can add links to other things and itbecomes just as useful as anything else.
55:46mytoots archives Mastodon toots
Sacha: You're saying this can flowinto Mastodon and from there, once you toot it...I think you're using mytootsthat you mentioned in your config forarchiving it?Or searching, yeah, okay.Oh, except it's currently not working.Ben: Yeah, I don't have it loaded right now.So mytoots, it just loads the backup ofyour export archive.So it loads the...What's the most recent one?So yeah, it was your outbox JSON file, which isthe most recent one here.I've got an Org Mode reminder to download itroughly quarterly.My outbox is about 100 megs right now.Compared to 4.5 gigs for elfeed,it's not so big.That's not going to redraw properly.I was just going to show it. My residentEmacs memory size right now is about like five orsix gigs.It's a little bit embarrassing.By comparison, 100 megs of JSON in RAM is not sobad, but having an instant search foreverything that you posted and being able tobounce back from your local archive to theconversation thread that's live and see anythingnew that comes in...Again, it lets me exercise that outboard brainkind of idea.So yeah, mytoots is super useful.Sacha: I like it a lot.
57:06Mentoring offer
Sacha: The last thing that I want to askbefore the kiddo (because I have twominutes) is that you have a mentoring offerpinned in your Mastodon, too.Have people taken you up on it, especially ifthey've taken you up on Emacs?Is that ongoing or forgotten about or whatever?Ben: Not forgotten about.Very much real.Still open.I haven't refreshed that offer recently, but it'sstill pinned for a reason.I think maybe a dozen or so folks haveasked for that.9 or 10 success stories, I think.Nobody's asked for Emacs tutorialship yet.That's fine.Again, I love Emacs.I use it.I don't often recommend it.But if anybody was curious about that, I would bevery open to the idea.Sacha: All right, so if people want toalso develop a very interesting elfeed setup,they know who to talk to.Ben: Please, I would love that conversation.Sacha: Thank you so much.Yes, go ahead.
58:02A local instance of public-inbox can let you use Gnus to read mailing lists quickly
Ben: Oh yeah, there's just one lastthing I want to mention, and I realize we'reright up against time.I use Gnus. I use mu4e for email,but I use Gnus for reading mailing lists.I just wanted to strongly recommend toanybody who is thinking about it... This is amazing.You gotta do this.public-inbox lets you keep a complete localarchive of the entire mailing list.Searches are instant.Tracking threads is instant.Check it out.It's fantastic.Sacha: That's great becauseEmacs-devel has a gazillion threads. How do youeven keep track of all this stuff? But if you'vegot Gnus and if you've got this set up,then you're no longer dependent on the goodgraces of Gmane being around as an NNTP tomailing list gateway.@JonKishore11 wants to know if you have aYouTube channel. I'm guessing you don't yet.Ben: I don't really like my face very much.Sacha: Ping Ben on Mastodon and ask about this mentoringthing and then share your notes so we can alllearn from it.Thank you so much for today.I look forward to chatting with you more through toots.What is the verb, you know, in the fediverse?All right.Thank you so much.Sacha:
sachactube: only slightly panicking behind the scenes 🙂 Nudged Ben by Mastodon in case we got our wires crossed
sachactube: yay, he's here, just getting sound sorted
symbiopoyesis: Good morning
x_goose_x: hey gnomonnnnnn
CharlieBaker707: yay! love the split keyboard. recently bought one myself. i was getting shoulder and neck pain from so many hours keeping by hands close together, but the split let's my shoulder's relax.
ShaeErisson: How do you make a capture template to stay on-agenda and record decisions? Any tips?
PuercoPop: Regarding terminal emacs, did they need to adapt any keybindings to avoid clashses with the terminal keybindings?
AyanRaza-n1x: is that the creator of emacs?
Ray-On-Emacs: Yes! Google steals C-S-k, which I use to kill tabs to the right on Vivaldi!
CharlieBaker707: elfeed is like a distraction alleviation machine. I agree with Ben, I don't think I could consume any of this information outside of Emacs. Ads and even varying formats distract me too much.
JonKishore11: do he have YT
sachactube: Thanks for hanging out, everyone! =)
gnomon027: Thanks so much for running this whole series, @sachactube !!
Please note that planet.emacslife.com aggregates blogs, and blog authors might mention or link to nonfree things. To add a feed to this page, please e-mail the RSS or ATOM feed URL to sacha@sachachua.com . Thank you!