Learning Emacs is not about scouring through documents and memorizing facts.
Those who use Emacs fluently know that the real skill is knowing how to ask Emacs about Emacs. The answer to any question you might have about Emacs lives behind just two keys: M-x and C-h. If you internalize those, plus a handful of command prefixes for the auto-discovery commands, Emacs will teach you whatever you need to know, on demand.
2. Start with M-xmx
M-x (that's Alt-x) runs any command by name. That's cool, but what makes it really special is that it lets you auto-complete command names.
Press M-x, type in some input, press TAB (for 'complete this input') and Emacs filters the entire list of commands based on your input:
There are two important consequences for a beginner:
You never need to memorize a command you can describe. M-x will surface it from a vague memory of what that command looks like.
Each command shows its keybinding (if it has one) next to its name, so M-x doubles as a way to learn 'shortcuts' to invoke these commands.
3. The Help Commands
As promised, Emacs provides commands that let you answer questions about Emacs. These are often called Emacs's 'auto-discovery' commands, and they all start with a few intuitive prefixes:
describe- — shows the documentation for a specific named thing (a function, variable, key, or mode).
find- — takes you to the source code or definition behind a name.
xref- — navigates references and definitions across your code, like "find usages" and "jump to definition."
Info- / info- — opens and moves around Emacs's built-in manuals.
apropos- — searches by keyword when you don't know the exact name, listing everything that matches.
customize- — opens a graphical interface for inspecting and changing settings.
4. The Prefix Trick discovery
Now that we know M-x and the families of auto-discovery commands, we can leverage M-x to perform something I like to call the 'prefix trick'.
This trick surfaces all Emacs's auto-discovery facilities to you, meaning you don't have to remember the few hundred that exist. Instead you only have to remember the few individual prefixes they all begin with.
For example, every command that describes something (like a command, variable, function, etc…) starts with describe-. So once you know that prefix, you can surface all commands in that family.
Try it. Type M-x describe- and press TAB, and watch all the describe commands surface (see screenshot). You can do this same trick for any of the auto-discovery commands described above.
The large number of help commands should be an indication of why this trick is useful!
Here are more screenshots for the other prefixes.
4.1.find-
4.2.xref-
4.3.Info- / info-
4.4.apropos-
4.5.customize-
5.C-h C-h Help Cheatsheet help
C-h (Control-h) is the universal "help" prefix. If you remember one thing from this post, remember C-h C-h — help for help. It opens a buffer listing every kind of help available (see screenshot). You will see the auto-discovery commands described above, as well as some other useful ones. Go explore!
6. More Magic with which-key
Since Emacs 30, which-key is built into Emacs. Enable it, then type the first part of a keybinding, and you'll see all the commands and their associated keybindings that fall under that prefix key. You even get documentation for the commands in a popup when you mouse over the command names! See the screenshot for this in action with C-h, the help prefix key.
Like with C-h C-h, you see all the help commands you can run via the C-h prefix key. Note this works on any prefix key, and even works without a prefix key at all with which-key-show-top-level. In this way, you don't even need to be aware of a prefix key at all, you can discover them all with which-key.
7. The Coda emacs
Again, you don't learn Emacs by memorizing stuff. Instead, you learn three things:
M-x to find (and run) commands,
the prefixes of the auto-discovery commands (describe-, find-, xref-, Info- / info-, apropos-, customize-) to enumerate the rest with TAB, and
C-h C-h to find every kind of help
From there, Emacs documents itself, all the way down to its own source code.
Note, this post is the shorter version of a longer, sillier post, with a valuable 'prefix trick' that alleviates the burden of memorizing anything I described in the original post.
He begins by noting that the help system is self-recursive is the sense that you can ask the help system about the help system. You simply call the help-for-help command intuitively bound to Ctrl+hCtrl+h. If you’ve never tried it, try it now. It gives you a nice listing of every help command.
Once you invoke help for a certain command or variable, you get a buffer containing a description of the command or variable as well as links to related commands/variables and the source code of the command so you can see exactly what it does and how it does it. You can discover what command a shortcut calls or what the shortcut for a command is with a simple help call.
There are a bunch of other aspects to the help system. You can, for example, get a listing of what your last commands were, complete information about the character at point, the current value of a variable, the current mode, and lots more.
For discovery, there are the apropos command and its siblings to help you find what you’re looking for even if you have no idea of its name. You merely need to have a general description of what it does. Fuzzy completion on command invocation (Meta+x) helps you find the right command even if you have only a vague idea of its name.
Hoplland’s post is long and has a lot of information but it’s one that every Emacs n00b—or more experienced user, for that matter—should read. In Holland’s terminology, it’s the first node in the Emacs knowledge graph.
Karthik Chikmagalur recently published another of his excellent
"Even More Batteries Included with Emacs"
posts, digging into lesser-known features that already ship with Emacs
today. I wanted to write its mirror image. His post covers the
batteries already in the box. Mine covers the ones arriving in Emacs
31.
Emacs 31 isn't out yet, but I've been building it from both emacs-31
branch and master and daily driving it for months. Every time
something new and useful lands, I fold it into Emacs
Solo, my no-external-packages
config, and mark it with a small ; EMACS-31 comment so I remember to
revisit it once the release is official.
This post walks those breadcrumbs. Every change below is one I'm
touching in my config right now, with a note on what it does and why I
keep it. None of it requires a package. It's all either on master
already or close behind.
One disclaimer: Emacs 31 is still in development (actually in
pre-release phase), so names and defaults can shift before final
release. Everything below is what I'm running as of mid-2026. If
you're not building from emacs-31 branch or master, treat this as
a preview of what's coming.
Tree-sitter that just works
If I had to pick the single change I'm happiest about, it's this one.
For years, getting a *-ts-mode going meant manually populating
treesit-language-source-alist, calling
treesit-install-language-grammar, and praying your toolchain was set
up to compile the grammar. In Emacs 31 a lot of that ceremony goes
away:
treesit-enabled-modes set to t switches the major modes that have
a tree-sitter variant over to it, and treesit-auto-install-grammar
makes Emacs offer to fetch and build the grammar when it's missing
instead of erroring out (more options are available like 'ask and
'ask-dir). This is the treesit-auto package experience, except now
the core does the work.
The knock-on effect shows up all over my config. I used to keep lines
like these around to teach Emacs where each grammar lives:
In Emacs 31 the grammar sources for languages like TypeScript, TSX,
Rust, TOML, YAML and Dockerfile live inside the modes themselves, so
I've got a trail of ;; EMACS-31 this is now defined on mode code
comments marking every block I get to delete once 31 ships. I'll take
less config that does the same job any day.
One foot-gun worth flagging if you share your Emacs directory tree
across machines of different architectures: the auto-installed grammars
are not segregated by architecture. An x86_64.so and an
arm64 one land under the same name, so the binary built on one
machine won't load on the other. Something to keep in mind.
There are many more tree-sitter improvements coming to Emacs. The
developers have been working tirelessly on it, Yuan Fu, along with
many others, have been continuously improving the tree-sitter
experience across multiple areas. From better language support to
usability and performance enhancements, tree-sitter in Emacs continues
to evolve at a remarkable pace.
A built-in markdown-ts-mode (experimental)
Emacs 31 ships a markdown-ts-mode in the box, and this one is close
to my heart. I started it. It grew out of a proposal I sent to
emacs-devel
back in early 2025, where the idea and the first version of the code
were mine.
I'd be doing the mode a disservice if I let you think it's a solo
effort. Stéphane Marks came along a bit later, rolled up his
sleeves, and has since become a co-author of the mode. He's the energy
behind much of what makes it nice to use today. He didn't send a patch
or two and move on; he stayed, pushing the mode well past what I'd
sketched out and sweating the details that turn "it works" into "it's a
pleasure." Much of the polish I'm about to brag about is his. The mode
is ours now, and it's better for it.
Watching an idea make the round trip from a mailing-list message to
core code, and picking up a great collaborator on the way, is one of
the most rewarding things about hanging around the Emacs community.
(use-package markdown-ts-mode
:ensurenil:defert)
It gives you more than colors, and these are the parts I want to show
off:
✔️ Org users will feel at home. The keybindings and editing feel
stay close to Org: navigating headings, folding sections, moving
between structural elements. If your fingers know Org, you won't have
to relearn Markdown.
✔️ Live, colored code blocks, even for non-tree-sitter languages.
This is my favorite trick. A fenced code block gets fontified using
the real major mode for that language, not dumped as flat
monospace. It reaches Emacs' own internal modes too, so an
```elisp block lights up with true Emacs Lisp
font-locking, and the other built-in modes do the same. You get
proper syntax highlighting inside your code samples with no extra
setup.
And it's not just colors: the code-block editing commands
largely work too, so you can edit a fenced block with the target
language's mode rather than fighting plain text. Completion inside
blocks is still the rough spot, that infrastructure is wonderfully
twisty and we haven't fully cracked it yet, so if you go poking,
that's where the bugs hide.
✔️ Inline image viewing. Image links render in the buffer, so a
Markdown doc with screenshots or diagrams reads like a document, not
a wall of  noise.
And many more features discoverable and being developed.
Together these make it feel like a comfortable place to write and
read Markdown inside Emacs, not a syntax highlighter bolted onto .md
files.
One caveat I want to be upfront about: markdown-ts-mode is still
experimental, and you have to opt into it. As the header of
markdown-ts-mode.el notes, it isn't wired up to auto-mode-alist
yet, so it won't take over .md files on its own. For now you pull in
the library with M-x load-library RET markdown-ts-mode, then turn it
on in a bufferf, or add it to auto-mode-alist yourself if you're
feeling brave.
Stéphane and I are working to get it considered ready by the next
Emacs release, and that's where you come in. If you try it and hit
rough edges, or it works great, we want to hear about it. Send
feedback to the bug
list with
M-x report-emacs-bug, or reach out to me and Stéphane directly.
Real-world use is what moves a mode from "experimental" to "done", so
don't be shy.
markdown-ts-view-mode gives you formatted hover docs without pulling
in anything extra. The same experimental caveat applies here, since
it leans on markdown-ts-mode, so treat it as something to opt into
rather than a finished default. I also turn off
eglot-code-action-indications. The new inline "you can do a code
action here" hints are clever, but some language servers make them
noisy, so I keep them off.
There's also some churn here: eglot-events-buffer-size is on its way
out in favor of eglot-events-buffer-config, so I've left a
;; EMACS-31 -- do we still need it? note on the old variable to clean
up later.
eldoc at point
A small one I'm fond of:
(eldoc-help-at-ptt);; EMACS-31
With this on, eldoc shows the help text for whatever sits under the
cursor, without me invoking anything. Paired with
eldoc-echo-area-prefer-doc-buffer, it makes wandering through
unfamiliar code feel more guided.
Smarter, eager completion
The minibuffer and completion machinery picked up a few new toggles:
completion-eager-update and completion-eager-display refresh the
completion UI as you type instead of waiting for you to ask. If you
don't run something like icomplete, setting eager display to t gives
you a sharp out-of-the-box experience on its own. And
minibuffer-visible-completions set to 'up-down lets you move
through the visible candidates with the arrow keys, which feels natural
at last.
icomplete got attention too, and this is another one I had a direct
hand in. Emacs 31 includes the patch from
bug#75784,
which I proposed and worked on. It brings vertical in-buffer behavior
and prefix indicators to icomplete. The side effect I like: a big
compatibility block I'd been carrying in my config can finally go away:
This is a fun set of new commands for rearranging your window layout
without manually splitting and killing windows:
("C-x w t". window-layout-transpose); EMACS-31("C-x w r". window-layout-rotate-clockwise); EMACS-31("C-x w f h". window-layout-flip-leftright); EMACS-31("C-x w f v". window-layout-flip-topdown); EMACS-31
Transpose swaps your horizontal and vertical arrangement, rotate spins
the whole layout around, and the flip commands mirror it left-to-right
or top-to-bottom. If you've ever built a three-window layout and then
wished the editor pane were on the other side, these do the job and
keep every buffer in place while they're at it.
A Speedbar that lives in a side window
Speedbar has been around forever, but in Emacs 31 it learned to live
in a proper side window instead of a separate frame:
(speedbar-window-default-width25);; EMACS-31(speedbar-window-max-width25);; EMACS-31;; bound to M-I in my config:(speedbar-window);; EMACS-31
speedbar-window docks it to the side like a modern file tree. On a
tiling setup or a single-monitor laptop, that beats the old
floating-frame behavior by a mile. A width cap keeps it from fighting
my other windows.
VC niceties
A few version-control improvements I've happily turned on:
vc-dir-auto-hide-up-to-date is the one I'm most pleased about.
Refreshing a vc-dir buffer now hides the up-to-date files on its own,
so I no longer need my g-key hack that called vc-dir-refresh
followed by vc-dir-hide-up-to-date. Another block marked for
deletion. vc-allow-rewriting-published-history nods to workflows like
Jujutsu and force-pushing feature branches, where rewriting
already-pushed history is a deliberate move.
Editable xref buffers
This one isn't a variable, it's a comment in my config reminding me to
remove a custom hack:
;; EMACS-31 Remove this, since new emacs will come with 'e' for editing xref buffers.;; Reference: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=80616
I'm going to indulge myself and tell the longer version of this one,
because I was part of it and it shows how features find their way into
Emacs.
The itch was this. Both Dired and grep buffers have long had an "edit"
workflow. In Dired you toggle into wdired-mode; in a grep buffer you
press e for grep-edit-mode. Bulk renaming and bulk
search-and-replace feel natural there. Xref buffers had no such thing.
The only editing operation was r (xref-query-replace-in-results),
which is regex-only and won't let you edit individual lines. I lean
hard on project.el and xref for navigating and refactoring, and I
kept catching myself re-running the same search with M-x grep to get
an editable buffer. An annoying detour, since xref already held all the
information needed.
So in March 2026 I sent a patch to bug-gnu-emacs proposing a small
command, xref-export-to-grep, bound to E in *xref* buffers. It
re-fetched the xref items, formatted them as file:line:content, and
dropped them into a grep-mode buffer where you could press e and edit
as usual. Nothing fancy. It bridged two things that already existed,
and I'd carried it as a personal snippet for a while.
What happened next is the part I love about this community. Dmitry
Gutov, who maintains xref, looked at it and pushed back on the UI of
my approach. My command created a hop between buffers, and once you
landed in the grep buffer you still had to know which key to press. He
asked a sharper question than the one I'd answered: did I care about
the grep export, or would it be better if xref buffers let you edit
inline?
That reframing was right. I told him I had no attachment to the grep
detour. Inline editing in the xref buffer itself, with multi-line
edits across matches, would kill the whole roundtrip. A few days later
he'd written and pushed xref-edit-mode. It drops the extra step and
runs faster on large xref buffers. My original xref-export-to-grep
could still go in as an optional command without a default binding,
but the inline mode is the better answer and it's what I use now.
The thread didn't stop there. It spun off into a wider design chat with
Juri Linkov about the *-edit-mode family (occur/grep/xref, which
write each buffer normally) versus wdired's
queue-everything-then-C-x C-s model, and whether a future "live"
search UI might present results differently. For the record, here's the
safety net I mentioned in that thread, a trick I picked up from
Protesilaos that lets me hit d to diff a buffer against its file
before saving during save-some-buffers:
(add-to-list'save-some-buffers-action-alist(list"d"(lambda(buffer)(diff-buffer-with-file(buffer-file-name buffer)))"show diff between the buffer and its file"))
Back to the topic, the end result: Emacs 31 ships editable xref
buffers, my config drops a homegrown workaround, and the feature that
landed beats the one I proposed, because the maintainer asked the
right question. Getting to play a small part in that loop is a big
chunk of why I enjoy living on master. The full back-and-forth is
public in
bug#80616 if
you're curious.
So, if you would like to try it. After C-x p g, grep for something
like FontAwesomeIcon. Now e starts the edit mode, make your edits,
C-c C-c to confirm.
ERC gets tidier
A couple of IRC improvements, since I live in ERC:
This makes ERC insert prenvious logs only for newly opened target
buffers, the behavior I want when rejoining channels. And one of my
favorite small fixes: in Emacs 31 the scrolltobottom module no longer
depends on erc-fill-wrap, so I can drop the conditional that used to
add it by hand for older versions. Thank you to whoever untangled that.
The grab bag of quality-of-life knobs
And then there's the long tail of tiny improvements that don't each
deserve a section but absolutely earn their place:
(delete-pair-push-markt); EMACS-31: pushes a mark after; delete-pair so C-x C-x selects what was inside(ibuffer-human-readable-sizet); EMACS-31: KB/MB instead of raw byte counts(ielm-history-file-name ...); EMACS-31: IELM input history is finally persisted(kill-region-dwim'emacs-word); EMACS-31: C-w with no region kills a word(native-comp-async-on-battery-powernil); EMACS-31: stop native-comp jobs on battery(view-lossage-auto-refresht); EMACS-31: live-updating C-h l, great for teaching/debugging(display-fill-column-indicator-warningnil); EMACS-31(dired-hide-details-hide-absolute-locationt); EMACS-31: hide the absolute dir path in dired-hide-details-mode(world-clock-sort-order"%FT%T"); EMACS-31: sort the world clock sanely(zone-all-framest); EMACS-31(zone-all-windows-in-framet); EMACS-31(uniquify-after-kill-buffer-flagt); EMACS-31: renamed from the -p variant
A few of these are worth a sentence:
✔️ kill-region-dwim fixes a decades-old papercut. Set it to
'emacs-word and hitting C-w with no active region kills a word
backwards instead of signalling an error. No more "the mark is not
active" interruptions.
✔️ view-lossage-auto-refresh turns C-h l into a live view of
your last keystrokes. When I'm screen-sharing or teaching, people can
watch the keys I press in real time.
✔️ ielm-history-file-name lets my IELM scratch sessions survive a
restart, the way comint and the shell already do.
✔️ native-comp-async-on-battery-power nil saves the laptop: no
surprise fan spin-ups from background native compilation while I'm
unplugged on a train.
✔️ tty-tip-mode brings tooltips to the terminal, a nice touch for
those of us who run Emacs in -nw.
Honorable mention: term stops eating lines
This one gets no config line, because there's nothing to configure. A
bug got fixed, and it makes me happier than it has any right to.
For a long time, term (and ansi-term) had a nasty habit of
swallowing lines. Full-screen, cursor-addressing programs left the
display garbled, with rows eaten or misplaced as the program redrew.
That hit the exact programs you most want a real terminal for: htop,
nethack, anything curses-based was close to unusable inside Emacs'
terminal.
Emacs 31 fixes it. term redraws correctly now, and I can run htop
to watch processes or fire up nethack for a "quick" break without the
buffer turning into confetti. It sounds small, and it removes one of
the last reasons I had to reach for an external terminal emulator.
Honorable mention 2: Modus 5 themes!
Thanks to Protesilaos, Emacs now ships with several modus themes:
✔️ modus-operandi-deuteranopia -- Deuteranopia-optimized theme with a white background.
✔️ modus-operandi -- Elegant, highly legible theme with a white background.
✔️ modus-operandi-tinted -- Elegant, highly legible theme with a light ochre background.
✔️ modus-operandi-tritanopia -- Tritanopia-optimized theme with a white background.
✔️ modus-vivendi-deuteranopia -- Deuteranopia-optimized theme with a black background.
✔️ modus-vivendi -- Elegant, highly legible theme with a black background.
✔️ modus-vivendi-tinted -- Elegant, highly legible theme with a night sky background.
✔️ modus-vivendi-tritanopia -- Tritanopia-optimized theme with a black background.
Why bother running master?
People ask why I daily drive an unreleased Emacs. Same reason I run a
no-packages config: I want to know what's in the box, and the way to
learn what's coming is to live in it. Most of these changes are small,
yet they add up to an editor that needs less of my glue code each
release. Watching my config get shorter as the core absorbs things I
used to hand-roll is one of the quiet joys of being an Emacs user.
For the other side of this coin, the batteries already there waiting to
be found, go read Karthik's
post.
It's a great companion to this one. And to see every snippet above in
context, they're all in the
Emacs Soloinit.el, each
marked with that small ; EMACS-31 breadcrumb.
See you when 31 ships, at which point I get to go delete a pile of
code. Happy hacking.
Edit
2026-06-29: Updated treesit-auto-install-grammar to 'always.
2026-06-18: Thanks to Stéphane Marks for the careful read and
corrections. He flagged the tree-sitter architecture foot-gun for
shared config directories (now noted above), pointed out that
markdown-ts-mode's code-block editing commands work and not just the
highlighting, and caught that the VC variable is now
vc-dir-auto-hide-up-to-date, not the name I'd written.
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.
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!