Irreal: Ray On Diary

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.

-1:-- Ray On Diary (Post Irreal)--L0--C0--2026-06-17T15:46:09.000Z

Charlie Holland: Juneau Something? Emacs Teaches You How to Fish!

1. TLDR   tldr

june-fish-banner-2.avif

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   emacs carnival builtins

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)   thesis recursion

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 k is 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?"   help tutorial

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."

help-for-help.png

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?"   introspection history

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?"   introspection eldoc

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?"   discoverability keys

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?"   help apropos

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?"   info documentation

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?"   source xref

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"   eval repl

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?"   customize config

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 🎣   demo games

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!):

  1. Open the source. M-x find-library RET tetris RET ("How does it actually work?") displays tetris.el in a buffer.
  2. 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.
  3. 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!
  4. 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.
  5. 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.
  6. 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.

june-graph.avif

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. 😉

-1:-- Juneau Something? Emacs Teaches You How to Fish! (Post Charlie Holland)--L0--C0--2026-06-17T13:35:59.000Z

Raymond Zeitler: Emacs Carnival: diary, Part 1

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:
  • column editing
  • keystroke recording and playback
  • regular expression search and replace
  • undo
  • support multiple files in multiple windows
2Calendar/Diary in the GNU Emacs Manual

-1:-- Emacs Carnival: diary, Part 1 (Post Raymond Zeitler)--L0--C0--2026-06-17T02:25:30.843Z

Protesilaos: Emacs: testing common colour values with the doric-themes

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.

(defconst test-doric-accents
  '( fg-red fg-green fg-yellow fg-blue fg-magenta fg-cyan
     bg-red bg-green bg-yellow bg-blue bg-magenta bg-cyan))

(dolist (accent test-doric-accents)
  (custom-declare-face
   (intern (format "test-doric-%s" accent))
   nil
   "Test."
   :group 'doric-themes))

(defun test-doric-set-accent-faces ()
  (doric-themes-with-colors
    (let* ((predicate (lambda (symbol) (string-prefix-p "bg" (symbol-name symbol))))
           (foregrounds (seq-remove predicate test-doric-accents))
           (backgrounds (seq-filter predicate test-doric-accents))
           (foreground-faces (mapcar
                              (lambda (accent)
                                `(,(intern (format "test-doric-%s" accent))
                                  ((t :foreground ,(symbol-value accent)))))
                              foregrounds))
           (background-faces (mapcar
                              (lambda (accent)
                                `(,(intern (format "test-doric-%s" accent))
                                  ((t :background ,(symbol-value accent) :foreground ,fg-main))))
                              backgrounds)))
      (apply #'custom-set-faces (append foreground-faces background-faces)))))

(add-hook 'doric-themes-after-load-theme-hook #'test-doric-set-accent-faces)

(defun test-doric-show-accents ()
  (interactive)
  (let ((buffer (get-buffer-create "*test-doric-themes-accents*")))
    (with-current-buffer buffer
      (erase-buffer)
      (dolist (accent test-doric-accents)
        ;; Pangram from my `show-font' package...
        (let* ((text "Protesilaos may find zesty owls and quiet jays vexing the black cat")
               (styled (propertize text 'face (intern (format "test-doric-%s" accent)))))
          (insert (format "%s\n" styled)))))
    (display-buffer buffer)))

Reload the theme for changes to take effect.

And, yes, I had the motivation to write this because I am developing new themes.

Doric themes sources

-1:-- Emacs: testing common colour values with the doric-themes (Post Protesilaos)--L0--C0--2026-06-17T00:00:00.000Z

Dave Pearson: become.el v1.4.0

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:

(use-package become
  :ensure t
  :defer t
  :vc (:url "https://github.com/davep/become.el" :rev :newest)
  :commands become-free-of-trailing-whitespace
  :init
  (unless noninteractive
    (add-hook 'before-save-hook #'become-free-of-trailing-whitespace))
  :bind
  ("<f12> <tab>" . become-freshly-indented-no-tabs))

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:

(cl-flet ((is-sig-line ()
                       (save-excursion
                         (beginning-of-line)
                         (looking-at "^-- $")))
          (markdown-br-p ()
                         (save-excursion
                           (beginning-of-line)
                           (and (eq major-mode 'markdown-mode)
                                (looking-at "^.+[^ ]  $")))))
; ...body removed
)

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.


  1. The header for become.el says 2017, but I think the header itself came a little later when I did some more work on my config

  2. And if you don't know, now you do

-1:-- become.el v1.4.0 (Post Dave Pearson)--L0--C0--2026-06-16T15:19:59.000Z

Irreal: Scrolling PDFs In Other Windows

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.

-1:-- Scrolling PDFs In Other Windows (Post Irreal)--L0--C0--2026-06-16T14:28:32.000Z

Meta Redux: CIDER 1.22 (“São Miguel”)

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:

  • Port - a minimalist prepl client for Emacs.
  • 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!

  1. If you ever get the chance to visit, do it. Crater lakes, hot springs, and the greenest hills you’ve ever seen. 

-1:-- CIDER 1.22 (“São Miguel”) (Post Meta Redux)--L0--C0--2026-06-16T09:00:00.000Z

Dave Pearson: More mode line tweaking

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.

Slightly updated mode line

The core of my mode line configuration now looks like this:

(setq mood-line-format
      (mood-line-defformat
       :left
       ((or
         (mood-line-segment-buffer-status)
         (propertize
          (mood-line--get-glyph :buffer-modified)
          'face 'my/mood-line-good-status))
        " "
        (mood-line-segment-buffer-name)
        (my/mood-line-segment-project)
        " "
        (mood-line-segment-major-mode))
       :right
       ((my/mood-line-segment-vc)
        " "
        (propertize
         (mood-line-segment-cursor-position)
         'face 'my/mood-line-cursor-position))))

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.

-1:-- More mode line tweaking (Post Dave Pearson)--L0--C0--2026-06-15T18:47:15.000Z

Marcin Borkowski: Scrolling pdfs in other windows

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!
-1:-- Scrolling pdfs in other windows (Post Marcin Borkowski)--L0--C0--2026-06-15T16:05:33.000Z

Sacha Chua: 2026-06-15 Emacs news

Lots of discussion around Karthik's latest blog post Even More Batteries Included with Emacs (Reddit, HN, lobste.rs). Check it out!

Links from reddit.com/r/emacs, r/orgmode, r/spacemacs, Mastodon #emacs, Bluesky #emacs, Hacker News, lobste.rs, programming.dev, lemmy.world, lemmy.ml, planet.emacslife.com, YouTube, the Emacs NEWS file, Emacs Calendar, and emacs-devel. Thanks to Andrés Ramírez for emacs-devel links. Do you have an Emacs-related link or announcement? Please e-mail me at sacha@sachachua.com. Thank you!

View Org source for this post

You can comment on Mastodon or e-mail me at sacha@sachachua.com.

-1:-- 2026-06-15 Emacs news (Post Sacha Chua)--L0--C0--2026-06-15T13:54:28.000Z

Irreal: Dired Flat File Listings

It turns out that if you call Dired from Elisp, you can pass it a list of files to display. Protesilaos Stavrou (Prot) leveraged that fact to write a bit of Elisp that provides him with a flat list of files matching a regular expression in a specified directory structure. His post has the code so you can see how he did it but it’s mostly what you’d expect: after some setup, he calls directory-file-recursively to gather the list of files that he then passes on to Dired.

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.

-1:-- Dired Flat File Listings (Post Irreal)--L0--C0--2026-06-14T14:57:27.000Z

TAONAW - Emacs and Org Mode: Meta Journal Notes in denote-journal with Journelly

Wow, I’m so good at overcomplicating things, I already made you go “huh?!” with the title alone! I have some mad skillz!

On with the show:

In the last couple of weeks, I slowly improved and tinkered with my Linux environment (Kubuntu). I’m not sure if it was a single thing that nudged me to do that, but between installing the latest version of Harper and switching to Vivaldi with its great features I keep discovering, I also started using denote-journal.

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:

Auto-generated description: A list of journal files, organized by date and day of the week, is shown in a directory format.

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.

-1:-- Meta Journal Notes in denote-journal with Journelly (Post TAONAW - Emacs and Org Mode)--L0--C0--2026-06-14T13:41:16.000Z

Dave Pearson: blogmore.el v5.3.0

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.

-1:-- blogmore.el v5.3.0 (Post Dave Pearson)--L0--C0--2026-06-14T07:49:14.000Z

Karthik Chikmagalur: Even More Batteries Included with Emacs

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.

Parts 1 & 2:

“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
(defun my/search-occur-browse-url (&optional use-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 ((match nil)
        (match-data nil)
        (context
         (lambda (beg &optional shrp)
           (let* ((before (string-replace
                           "\n" ""
                           (buffer-substring-no-properties
                            beg (max (line-beginning-position) (- beg 30)))))
                  (link (string-replace
                         "\n" "" (buffer-substring-no-properties beg (point))))
                  (after (buffer-substring-no-properties
                          (point) (min (line-end-position) (+ (point) 30)))))
             (concat (propertize " " 'display '(space :align-to 65))
                     (propertize (concat "…" before) 'face 'shadow)
                     (if shrp
                         (propertize link 'face '(:inherit shadow :weight bold
                                                           :underline t))
                       link)
                     (propertize (concat after "…") 'face 'shadow))))))
    (save-excursion
      (goto-char (point-min))
      (while (search-forward-regexp my/search-url-regexp nil t)
        (push (cons (match-string-no-properties 0)
                    (funcall context (match-beginning 0)))
              match-data))
      (goto-char (point-min))
      (while (setq match (text-property-search-forward 'shr-url nil nil))
        (push (cons (prop-match-value match)
                    (funcall context (prop-match-beginning match) 'shrp))
              match-data)))
    (let* ((completion-extra-properties
            `(:annotation-function
              ,(lambda (cand) (concat " " (cdr (assoc cand match-data))))))
           (url (completing-read "Browse URL: " match-data nil t)))
      (if use-generic-p
          (browse-url-generic url)
        (browse-url url)))))

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
  1. Move the cursor to the beginnings of the text to compare in two windows.
  2. M-x compare-windows
  3. 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
  1. Two directories containing some similar-looking files.
  2. Place the cursors on the same file in both windows.
  3. M-x compare-windows
  4. 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.

Highlight buffer changes (M-x highlight-changes-mode)

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:

(defun highlight-changes-mode-turn-off ()
  (and highlight-changes-mode (highlight-changes-mode -1)))

(defun highlight-changes-auto ()
  (when (buffer-file-name)
    (highlight-changes-mode-turn-on)
    (add-hook 'after-save-hook #'highlight-changes-mode-turn-on nil t)
    (add-hook 'before-save-hook #'highlight-changes-mode-turn-off nil t)))

(add-hook 'text-mode-hook #'highlight-changes-auto)

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)
(defun highlight-changes-mode-turn-off ()
  (and highlight-changes-mode (highlight-changes-mode -1)))

(define-minor-mode highlight-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-mode 1)
    (add-hook 'after-save-hook #'highlight-changes-mode-turn-on nil t)
    (add-hook 'before-save-hook #'highlight-changes-mode-turn-off nil t))
   (t (highlight-changes-mode -1)
      (remove-hook 'after-save-hook #'highlight-changes-mode-turn-on t)
      (remove-hook 'before-save-hook #'highlight-changes-mode-turn-off t))))

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
(defun my/read-backup-file-name (file)
  (if-let* ((backup-files (file-backup-file-names file)))
      (completing-read "Backup version: " backup-files nil t)
    (user-error "No backup files available for file %s" (buffer-file-name))))

(defun my/vc-diff (&optional arg)
  "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-case errdata (call-interactively #'vc-diff)
      (error
       (if (string-match-p "not under version control" (cadr errdata))
           (if arg
               (diff (my/read-backup-file-name (buffer-file-name))
                     (buffer-file-name))
             (diff-backup (buffer-file-name)))
         (apply #'signal errdata))))))

(defun my/vc-ediff (&optional arg)
  "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-case errdata (call-interactively #'vc-ediff)
      (error
       (if (string-match-p "not under version control" (cadr errdata))
           (if arg
               (ediff-files (my/read-backup-file-name (buffer-file-name))
                            (buffer-file-name))
             (ediff-backup (buffer-file-name)))
         (apply #'signal errdata))))))

(defun my/vc-revision-other-window (&optional arg)
  "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-case errdata (call-interactively #'vc-revision-other-window)
    (error
     (if (string-match-p "not under version control" (cadr errdata))
         (if arg
             (find-file-other-window (my/read-backup-file-name (buffer-file-name)))
           (if-let* ((backup (file-newest-backup (buffer-file-name))))
               (find-file-other-window backup)
             (user-error "No backup files available for %s" (buffer-file-name))))
       (apply #'signal errdata)))))

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-keymap help-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-set help-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”.

find-func goodies (M-x find-function-on-key, M-x find-function)

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:

  1. Find the command invoked by the key: describe-key or C-h k + your key sequence.
  2. Jump to its definition by pressing s (for “source”).
  3. 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-set help-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:

      (define-advice copy-from-above-command (:around (func &optional arg) comment)
        (if (equal current-prefix-arg '(4))
            (progn
              (funcall func)
              (save-excursion
                (forward-line 0)
                (let ((ln (line-number-at-pos (point))))
                  (backward-char)
                  (skip-chars-backward "\n\t ")
                  (unless (= (line-number-at-pos) ln)
                    (comment-line 1)))))
          (funcall func arg)))
    

    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:

      (setq duplicate-region-final-position -1
            duplicate-line-final-position -1)
    

Turn keystrokes into macros (M-x kmacro-edit-lossage)

Three facts about Emacs keyboard macros:

  1. 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.
  2. 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.
  3. 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:

  Nomenclature           Subwords
  ===========================================================
  GtkWindow          =>  "Gtk" and "Window"
  EmacsFrameClass    =>  "Emacs", "Frame" and "Class"
  NSGraphicsContext  =>  "NS", "Graphics" and "Context"

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:

(add-hook 'lisp-data-mode-hook
          (lambda () (modify-syntax-entry ?: "w")))

In Org mode, it’s treating the delimiters = and ~ as word constituents:

(add-hook 'org-mode-hook
          (lambda ()
            (modify-syntax-entry ?= "w")
            (modify-syntax-entry ?~ "w"))

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

(setq other-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:

(setq other-window-scroll-default
      (lambda ()
        (or (get-mru-window nil nil 'not-this-one-dummy)
            (next-window)               ;fall back to next window
            (next-window nil nil '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!


  1. 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. ↩︎

-1:-- Even More Batteries Included with Emacs (Post Karthik Chikmagalur)--L0--C0--2026-06-14T07:05:00.000Z

Bicycle for Your Mind: Separate Writing and Formatting

writingwriting

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.

macosxguru at the gmail thingie.

Thanks to: Photo by Pixabay: https://www.pexels.com/photo/remington-standard-typewriter-in-greyscale-photography-163116/

-1:-- Separate Writing and Formatting (Post Bicycle for Your Mind)--L0--C0--2026-06-14T07:00:00.000Z

Dave Pearson: It got darker

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
  • It caused Emacs to crash1

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!

An even darker Emacs

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...


  1. Seriously, just the once, but that happened. I took that as a sign from the Lisp gods that I was doing something sinful. 

-1:-- It got darker (Post Dave Pearson)--L0--C0--2026-06-13T09:49:48.000Z

Protesilaos: Emacs: flat Dired listing for REGEXP, optionally up to DAYS since last modification

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:

(defvar prot-dired-regexp-history nil
  "Minibuffer history of `prot-dired-regexp-prompt'.")

(defun prot-dired-regexp-prompt ()
  (let ((default (car prot-dired-regexp-history)))
    (read-regexp
     (format-prompt "Files matching REGEXP" default)
     default 'prot-dired-regexp-history)))

(defun prot-dired--get-files (regexp)
  "Return files matching REGEXP, recursively from `default-directory'."
  (directory-files-recursively default-directory regexp nil))

;;;###autoload
(defun prot-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-files regexp))
            (relative-paths (mapcar #'file-relative-name files)))
      (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:

(defvar prot-dired-days-prompt-history nil
  "Minibuffer history for `prot-dired-days-prompt'.")

(defun prot-dired-days-prompt ()
  "Prompt for days and return them as a number."
  (let* ((first (car prot-dired-days-prompt-history))
         (default (when (stringp first)
                    (string-to-number first))))
    (read-number "Number of days: " default 'prot-dired-days-prompt-history)))

(defun prot-dired--get-last-modified (files days)
  "Return list of FILES last modified since DAYS."
  (seq-filter
   (lambda (file)
     (and-let* ((attributes (file-attributes file))
                (last-modified (nth 5 attributes))
                (last-modified-seconds (time-to-seconds last-modified))
                (current-time (current-time))
                (current-time-seconds (time-to-seconds current-time))
                (delta-seconds (* days 24 60 60))
                (oldest-seconds (- current-time-seconds delta-seconds))
                (_ (>= last-modified-seconds oldest-seconds)))))
   files))

;;;###autoload
(defun prot-dired-search-flat-list-since-days (regexp days)
  "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-files regexp)))
      (if-let* ((files-filtered (prot-dired--get-last-modified files days))
                (relative-paths (mapcar #'file-relative-name files-filtered)))
          (dired (cons (format "prot-flat-dired since %d days for `%s'" days regexp) 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.

-1:-- Emacs: flat Dired listing for REGEXP, optionally up to DAYS since last modification (Post Protesilaos)--L0--C0--2026-06-13T00:00:00.000Z

Dave Pearson: Simplifying my mode line

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:

(setq mood-line-format
      (mood-line-defformat
       :left
       (((mood-line-segment-buffer-status) . " ")
        ((mood-line-segment-buffer-name) . " : ")
        (mood-line-segment-major-mode))
       :right
       (((mood-line-segment-vc) . "  ")
        (mood-line-segment-cursor-position))))

So far I'm really pleased with the result.

My GNU Emacs

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.

-1:-- Simplifying my mode line (Post Dave Pearson)--L0--C0--2026-06-12T18:06:26.000Z

Irreal: AsciiDoc In Emacs

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.

-1:-- AsciiDoc In Emacs (Post Irreal)--L0--C0--2026-06-12T14:22:51.000Z

Dave Pearson: blogmore.el v5.2.0

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:

title: "blogmore.el v5.2.0"
date: "2026-06-12 08:31:15+0100"
category: Emacs
tags:

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.

-1:-- blogmore.el v5.2.0 (Post Dave Pearson)--L0--C0--2026-06-12T07:31:15.000Z

Dave Pearson: blogmore.el v5.1.0

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:

(defmacro blogmore--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-name nil
         ,(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-name dump-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:

(blogmore--cache-dump categories)
(blogmore--cache-dump tags)
(blogmore--cache-dump series)

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.

-1:-- blogmore.el v5.1.0 (Post Dave Pearson)--L0--C0--2026-06-11T18:06:24.000Z

Lars Ingebrigtsen: Web scraping is getting harder all the time

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.

Guess what I chose!

The result is on Microsoft Github.

The idea is:

  1. First try to fetch the URL using the normal, fast method.
  2. If this fails, use Selenium headless. This involves spinning up a web browser and then dumping the resulting DOM.
  3. 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.

*sigh*

These are the days of your life…

-1:-- Web scraping is getting harder all the time (Post Lars Ingebrigtsen)--L0--C0--2026-06-11T16:06:01.000Z

Raymond Zeitler: Creating a Reference to a Webpage in Org

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


1 Sacha Chua's Emacs Chat with Raymond Zeitler transcript. Please scroll to 35:50

2 I use a clipboard manager so that I can copy content to the clipboard multiple times without clobbering all but the most recent item.

3 https://sachachua.com/blog/2025/07/emacs-open-urls-or-search-the-web-plus-browse-url-handlers/
-1:-- Creating a Reference to a Webpage in Org (Post Raymond Zeitler)--L0--C0--2026-06-11T15:42:30.885Z

Irreal: An Emacs Based Writerdeck

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.

-1:-- An Emacs Based Writerdeck (Post Irreal)--L0--C0--2026-06-11T14:48:00.000Z

Raymond Zeitler: Emacs -- It's Worth Revealing Oneself For

"...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

Thank you, again, Sacha!


1Sacha Chua, https://sachachua.com/blog/2026/05/emacs-chat-with-raymond-zeitler/#ID-ec23-transcript
2https://www.emacswiki.org/emacs/RaymondZeitler
3Sacha Chua, ibid.

2026-06-11 Fix link in footnote 1.
-1:-- Emacs -- It's Worth Revealing Oneself For (Post Raymond Zeitler)--L0--C0--2026-06-11T14:41:42.159Z

Charlie Holland: Emacs SVG Benchmark Reveals Gaming-Caliber Frame Rates

1. TLDR

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).

(defun svg-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).

-1:-- Emacs SVG Benchmark Reveals Gaming-Caliber Frame Rates (Post Charlie Holland)--L0--C0--2026-06-11T12:10:09.000Z

Bozhidar Batsov: Emacs loves AsciiDoc

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!

  1. Also, I really wanted to name something asciidoc-mode↩︎

  2. Afterwards we’ll aim for world domination, of course. ↩︎

-1:-- Emacs loves AsciiDoc (Post Bozhidar Batsov)--L0--C0--2026-06-11T06:00:00.000Z

Alvaro Ramirez: agent-shell 0.55 updates

It's been a little while since my last agent-shell update, so let's go through the latest highlights as of v0.55.

What's agent-shell?

agent-shell is a native Emacs mode to interact with AI agents powered by ACP (Agent Client Protocol).

Picking up where I left off

If you noticed slower project activity in April, this is why. I'm getting better at the new 24-hour job, so I've resumed working on agent-shell.

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.

Anthropic, Google, and why ACP matters

With Anthropic's SDK subscription support changing, Google's Gemini CLI deprecation, and Antigravity's unclear support for the Agent Client Protocol (ACP), vendor-neutral tools matter more than ever.

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.

agent-shell needs your support

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 ;)

GitHub stars for Anthropic credit

Anthropic offers 6 months of free Claude Max 20x for qualifying open-source projects with at least 5,000+ GitHub stars. Starring agent-shell costs nothing and can save me some money. We're only a 5th of the way there ;) so if you don't mind a couple of clicks, the project can really use another GitHub star.

Speaking of GitHub stars, agent-shell is now my most popular Emacs package, recently overtaking chatgpt-shell.

Star History Chart

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.

Note that anything but minimal verbosity is fairly new, so please report bugs or rough edges.

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.

Improved folding

Folding got smarter (#608 by @codeluggage):

  • 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"
  • 19: 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.

To get the previous word-based label back:

(setq agent-shell-status-kind-label-function
      #'agent-shell--inverse-label-status-kind-label)

Codex defaults

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:

Pull requests

Thank you to all contributors for these improvements!

Bug fixes

  • #202: Header icon is double the expected size
  • #278: Heartbeat causes high CPU usage with many agent buffers
  • #366: .agent-shell/ directory at risk when switching git branches
  • #400: agent-shell-viewport-reply-1 errors with "Text is read-only"
  • #401: Garbled characters output when using non-English languages
  • #412: Diff buffer management is messy
  • #414: agent-shell-mode-hook timing makes subscribing to events difficult
  • #417: Unhandled notifications with kiro
  • #426: Starting conversation before agent has initialized leaves "dangling" text
  • #431: Heartbeat timer keeps running after failed/abandoned authentication in OpenAI
  • #435: xclip clipboard handler silently saves text as PNG in terminal mode
  • #441: Background agent notifications treated as stale after session/prompt response
  • #443: image-type: Invalid image type 'svg on calling agent-shell
  • #455: agent-shell enters frozen/hanging state when receiving unknown notifications
  • #462: Header text invisible when font-get :size returns 0
  • #465: Session load crashes on non-text user message chunks (e.g. images)
  • #466: agent-shell-diff-accept-all / -reject-all now focus the originating shell
  • #468: wl-paste-image-handler breaks pasting text
  • #481: History input rolls back in insert editing mode while pressing up/down arrows
  • #485: Shells created in other workspaces no longer display
  • #493: Tables rendered in agent-shell break cursor (point) navigation
  • #533: Can't install agent-shell from MELPA
  • #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.

Sponsor agent-shell

-1:-- agent-shell 0.55 updates (Post Alvaro Ramirez)--L0--C0--2026-06-11T00:00:00.000Z

Irreal: Emacs In Pop Culture

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.

-1:-- Emacs In Pop Culture (Post Irreal)--L0--C0--2026-06-10T15:35:57.000Z

Chris Maiorana: When tmux is your window manager

I recently wrote a post about writerdecks and minimalist “distraction-free” writing environments in general. I concluded that the most minimalist writing environment you could get is a cheap notebook and Bic pen you could get at any supermarket.

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.

Thanks for reading, be sure to check out my books about similar topics: Emacs For Writers and Git For Writers.

The post When tmux is your window manager appeared first on Chris Maiorana.

-1:-- When tmux is your window manager (Post Chris Maiorana)--L0--C0--2026-06-10T11:56:45.000Z

Dave Pearson: blogmore.el v5.0.0

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:

tags: [BlogMore, Emacs, "Emacs Lisp", Lisp, "blogmore.el", coding]

or:

tags:
  - BlogMore
  - Emacs
  - Emacs Lisp
  - Lisp
  - blogmore.el
  - coding

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:

tags: [BlogMore, Emacs, "Emacs Lisp", Lisp, "blogmore.el", coding]

So if you have a bare list:

tags: BlogMore, Emacs, "Emacs Lisp", Lisp, "blogmore.el", coding

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.

The current menu

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.


  1. The benefits being: only values in frontmatter appear, inconsistent casing is cleaned up, etc. 

-1:-- blogmore.el v5.0.0 (Post Dave Pearson)--L0--C0--2026-06-10T09:22:12.000Z

James Dyer: The Hidden Git Stash Keys in Emacs VC Directory Mode

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:

20260610061920-emacs--The-Hidden-Git-Stash-Keys-in-Emacs-VC-Directory-Mode.jpg

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:

(defvar-keymap vc-git-stash-map
  :parent vc-git-stash-shared-map
  "<down-mouse-3>" #'vc-git-stash-menu
  "C-k"            #'vc-git-stash-delete-at-point
  "="              #'vc-git-stash-show-at-point
  "RET"            #'vc-git-stash-show-at-point
  "A"              #'vc-git-stash-apply-at-point
  "P"              #'vc-git-stash-pop-at-point)

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.

-1:-- The Hidden Git Stash Keys in Emacs VC Directory Mode (Post James Dyer)--L0--C0--2026-06-10T05:19:00.000Z

Rahul Juliato: This Blog Now Has a Gemini Mirror

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:

geminiprotocol.net/software

Pick one, type in the address above, and enjoy the quiet side of the internet. See you there!

-1:-- This Blog Now Has a Gemini Mirror (Post Rahul Juliato)--L0--C0--2026-06-09T20:55:00.000Z

Sacha Chua: From DC Toedt: Copy Org Mode as Markdown

: Add embark way to do things.

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:

Anyway, DC shared how he used Claude to generate a simple function to do it, which is here under public domain:

(defun my/org-to-markdown-clipboard ()
  "Export org region (or buffer) to Markdown and copy to clipboard.
With no active region, exports the whole buffer."
  (interactive)
  (require 'ox-md)
  (let* ((text (if (use-region-p)
                   (buffer-substring-no-properties (region-beginning)
(region-end))
                 (buffer-substring-no-properties (point-min) (point-max))))
         (md (org-export-string-as text 'md t '(:with-toc nil
                                                :with-author nil
                                                :with-date nil
                                                :with-title nil))))
    (kill-new md)
    (message "Markdown copied (%d chars)" (length md))))
(with-eval-after-load 'org
  (define-key org-mode-map (kbd "C-c m") #'my/org-to-markdown-clipboard))
View Org source for this post

You can e-mail me at sacha@sachachua.com.

-1:-- From DC Toedt: Copy Org Mode as Markdown (Post Sacha Chua)--L0--C0--2026-06-09T15:49:08.000Z

Dave Pearson: blogmore.el v4.7.0

A quick update to blogmore.el. Having recently added series support to BlogMore it made sense that I then add a quick way of adding a post to a series in the package.

Selecting a series

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.

Some time soon...

-1:-- blogmore.el v4.7.0 (Post Dave Pearson)--L0--C0--2026-06-09T07:42:40.000Z

Sacha Chua: Yay Emacs 33: Sacha and Prot Talk Emacs: Built-ins

: Updated transcript

I chatted with Prot about the Emacs Carnival June 2026 topic Underappreciated Emacs Built-ins. Thanks to Ross A. Baker for hosting the carnival!

View in the Internet Archive, watch or comment on YouTube, read the transcript online, download the transcript, or e-mail me.

Related links:

Chapters

  • 0:00 Starting up
  • 2:27 Focus and distraction
  • 3:54 Org Mode and other note-taking, task-management systems
  • 4:58 Kill ring
  • 6:50 Registers
  • 9:58 Narrowing
  • 12:04 org-narrow-to-subtree
  • 12:13 narrow-to-defun
  • 13:19 Indirect buffers
  • 14:50 Undoing within a region
  • 15:53 Bookmarks
  • 17:41 isearch
  • 18:21 Tip: Add a counter to isearch
  • 19:26 C-x C-x (exchange-point-and-mark)
  • 20:55 Popping to marks - going back to where you were
  • 21:49 Selecting what you just pasted
  • 22:33 Indenting pasted or selected text with indent-rigidly
  • 23:24 Popping to mark after xref or imenu
  • 24:05 Adding other packages like consult
  • 24:44 Tip about indicating isearch wrapping
  • 25:26 Navigating by sentence or s-expression
  • 27:45 Navigating to other errors
  • 28:29 Tags
  • 28:47 Imenu
  • 30:19 Projects
  • 32:10 Putting projects in tabs or frames
  • 32:35 Tabs
  • 34:41 Navigating frames
  • 36:07 These navigation shortcuts work for prose, too
  • 37:09 follow-mode
  • 37:50 Ediff
  • 42:12 Calling functions by name
  • 42:52 Completion
  • 44:13 Manuals
  • 45:57 Menus
  • 47:46 Automation - abbreviations
  • 49:56 Quoting the next character with C-q
  • 50:31 Mapping abbreviations to code
  • 51:51 Taking notes with org-capture
  • 52:08 Navigating back to captures or refiles
  • 53:49 dabbrev
  • 54:44 Keyboard macros
  • 57:52 Editable grep and occur
  • 1:01:01 Emacs Carnival June 2026: Underappreciated built-ins

Transcript

Expand this to read the transcript

0:00 Starting up

Sacha: There's a 10-second delay, so I can never quite tell when I'm starting to start, but I 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 about underappreciated Emacs built-ins, which is the theme for this month's Emacs carnival.

Sacha: Kind of like this, you know, shared, lots of people 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 very tempted to just dive into this brain dump like last time about... Let's start with the kinds of problems that newcomers and intermediate users might run into, especially the problems they don't even know about because Emacs would allow them to do things that 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 theirs and that Emacs can help them with it. So maybe this conversation can be a high-level discussion of these concepts to help people develop this intuition for what's out there, particularly for the things that Emacs does differently compared to other editors. And if we start with a problem, and I have several that I often run into in my own life, you might suggest others as well. Then we can talk about how the things that are built into Emacs can support that and how they fit together at a high level. We don't have to go into "This is precisely how to start a keyboard macro and how to stop it." People can look that up in the manual. But the idea of a keyboard macro and how it's useful, that would probably be a good thing for a conversation. Then for the advanced users who are listening to this, we can sprinkle in some things we've seen about some really advanced uses of these built-ins, because there's a lot of high-level use that I haven't even got into yet. So Prot is here, which means that because you've got two people, you can see how these same tools can be used in different ways to support different workflows. I'm going to suggest some problems that I have. Of course, you can share some from your experience and from the times that you've coached other people.

2:27 Focus and distraction

Sacha: My main problem with life in general. is focus and distraction. Because I have a kid, my focus time is very unpredictable. It can be interrupted any moment by somebody needing help. My life over the last 10 years has mostly been 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 my brain 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 the propensity 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 combine it with curiosity, because now you want to learn everything. 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 will not even try. I won't even go down the rabbit hole.

Sacha: So these are two sides of the same problem, and something that a lot of people will resonate with... When you're working on something and you realize, okay, I've got to go do this other thing first or, oh, I'm curious about this question that 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:54 Org Mode and other note-taking, task-management systems

Sacha: My first recommendation for this problem is: take advantage of Org Mode or other built-in note-taking task management support systems because it... Sometimes people think, okay, an IDE is just an IDE, right? If they're programmers, it's just for code. Sometimes people are writing. They're using a text editor just for writing their novel. But because Emacs has these built-in ways to support 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 list and put something in. Then it gets out of your brain so that you can try to focus on the thing that you're trying to get done. That's my quick underappreciated... actually, a lot of people really appreciate this, but it's one of those things people coming to Emacs from other editors might not immediately catch on to.

Prot: You might not understand the extent 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 couple of keystrokes away, and they can save the context of whatever you were looking at.

4:58 Kill ring

Sacha: There are all sorts of other small conveniences that Emacs has that also help with distraction 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 been part of Emacs for several versions now, but it's not obvious. If you type M-y without C-y beforehand, you get completion. So you can select something that you had in your kill-ring like a few kills ago. Clipboard navigation, which is something that you don't see right away.

Sacha: If people are coming from outside Emacs and they're like, "What is this thing that you're talking about?" People are used to having a clipboard, right? As soon as you copy something, your program forgets the thing that you previously copied. On mobile phones now, if you press paste, you can see a selection of the previous things you've copied before. It's like that, but larger.

Sacha: Prot points out: you can use completion with it. So M-y is yank-pop I think? What I find useful about this is sometimes I'll copy something because I want to go paste it somewhere else, and then on the way to that somewhere else, I get distracted by something, and I need to copy that, but I know that the kill-ring will have the other copies that I meant to put somewhere else.

Prot: By completion here, we mean you can 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:50 Registers

Sacha: Registers. It's the other thing that I like to use when I know that I'm copying several things and I need to paste them, possibly in different order.

Sacha: Again, that's another thing that people are like, "What is this thing, even?" Do you find yourself explaining registers to people who are new to Emacs?

Prot: Yes. Registers is something that is underutilized, because of course, why would you need them when you can have a kill-ring with a history, right? Why do I need to store things in a register when I can just have them one after the other in the kill-ring. The answer is because if you do something more advanced, 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 that to great effect. So that's one of those little Easter eggs for advanced users. If you're watching this and you're like, okay, I know about these built-ins, but there's more. Emacs has this fractal complexity. It just keeps getting more interesting the 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 window configurations, Prot?

Prot: I have used them for framesets: frames and their window configurations. If you have three frames and they are split in different ways, you restore that.

Sacha: You can do all of that with just one register.

Prot: With a register, yeah. I have created another register of mine just to see how it works, where it saves a file 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 to things like my Emacs configuration or my notes or something like that. I use that instead of bookmarks so that I can just have a keyboard shortcut go straight to that register. I can do the [jump-to-register] and then I can just easily press one more key to 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 features for helping you save text to things, especially if you're going to use them in keyboard macros because you can say, okay, insert text A and then insert text C and then insert text B. But you can also use them for other things like frameset, like the way that your windows and your buffers are arranged, or files that you want to go back to.

9:58 Narrowing

Sacha: Another built-in that I find really helpful for managing my focus and distraction is narrowing. I get distracted by all the other stuff, or I worry about accidentally revealing private information when I am streaming, or something else. So instead I narrow it to just the task that I'm working on or just the function that I'm editing. That's super useful not only for keeping me focused, but also for making sure that my changes don't affect more text than I mean to. If I'm using substitute.el... You can select the region, and a lot of the functions in Emacs will operate only within that region. But reselecting the region several times, if you end up needing to do multiple operations, it's a bit annoying. So instead, I'll just narrow and then it can work on the whole thing.

Prot: Yes. When you narrow, you can also 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 within that portion of the buffer. So if you take care to narrow to where you want to be, then okay yes to all, you don't even have to check.

Sacha: And I think this is underappreciated enough that, in fact, if you try to use… Is it C-x n?

Prot: That's the prefix key. C-x n for narrowing.

Sacha: The first time Emacs will say, 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 file disappears." I know it's there. I'm just choosing to focus on it. I think it's actually available off the menu as well, but I haven't used it off the menu bar.

Prot: Yeah, I don't use the menu, so I cannot 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:04 org-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:13 narrow-to-defun

Sacha: Narrowing to defun feels easier than trying to mark the function before search and replace. I love narrowing. In fact, I narrow to functions or sets of functions a lot, because I do a lot of work with with 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 copy the particular snippet of JavaScript so I can paste it into the console as I'm making changes. I have a function that looks for certain text: "start of focus", "end of focus". Then it narrows to that section, which might include several functions. Then I have another keyboard shortcut that just copies the entire buffer and adds a little text at the end, so I can run whatever function I need to test. I can paste that into the browser. Narrowing either to one function or to a predefined region or whatever else is very useful.

Prot: Yes, very nice.

13:19 Indirect buffers

Sacha: Then people are like, yeah, but what if I want to narrow to two parts of the same file?

Prot: That's why you have indirect buffers there.

Sacha: It's Emacs, of course there's a way to do it. Indirect buffers is another one of those built-ins that's a little hard to wrap your head around, because you're like, okay, you're opening a file twice, but you can have it narrowed to a different part of it, or you can be looking at a different part of it, or you can even have it in a different major mode.

Prot: Yeah, yeah. And the point, like the practical one, is the different levels of narrow, really... The most common one, I mean, where it's like, okay, you focus on this heading and now you focus on this other heading.

Sacha: I'll often split my buffer if I know that I'm not going to narrow. So that way, if I need to refer to two parts of the file at the same time, I can have one window focusing on one part of it and the other window focusing on the other part of it. It might even be a different frame. And that way, I don't have 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 other and 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 or whatever, then cloning an indirect buffer is the way to do it.

14:50 Undoing within a region

Prot: I don't know if you have this, but because you mentioned 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 works in the region. So you make a change here, you go make some changes up there, you come back here, you mark this region, undo only works here, it doesn't work up there anymore.

Sacha: Oh yeah, that's definitely a built-in that people will benefit from if they develop an intuition for it. If you've made a bunch of changes to your file and you notice that something's wrong in just this section, you can select the region and then undo within it to just fix those things. Those are some of the things that I've thought about for focus or distraction or getting tempted to go down rabbit holes. Do you use any of the other Emacs built-ins to help you with your tendency to dive really deep into something?

15:53 Bookmarks

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 not only it's a way to go to a place, but you also give it a name. So the counterpart... Like you said, okay, I have a key to quickly go to my init file, for example, my configuration file. But what if I want to have something by name that doesn'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, which is descriptive and gives me context. Then I use a bookmark for that.

Sacha: And that's a great built-in solution for the general problem of finding your way around. So in case you're trying to find your way around different files or different projects or different places in various files, bookmarks are great for that because you can give it a name. That means you can file more things than will fit on your keyboard. Kind of an advanced use of it, I was talking to Ben in the previous Emacs Chat about So he bookmarks Elfeed searches, and based on his naming convention, if he names his bookmark a certain way, then it becomes available for these other functions that he has. So if you have a naming convention for your bookmarks, you can do other things with it from Emacs Lisp.

Prot: Yeah, exactly. That's the more advanced power user thing. It's just data and you have access to it.

17:41 isearch

Sacha: Going back to something a little more basic for the problem of finding your way around, I think that isearch is one of those built-ins that people coming from a different editor might not think of using. "Find in page" is an annoying experience in a browser or in other editors. You have to go to the menu, you do it, and then there's things you have to click on in order to go to the next one or the previous one and so forth. But isearch lets you just keep typing and then you can just press the isearch shortcut again, C-s, to search for the next one, or you can go to the previous one very easily. So isearch is great.

18:21 Tip: Add a counter to isearch

Prot: Yeah, yeah, it is. I think one nice quality of life improvement to it, which again is several Emacs versions old, is a counter. Like it shows you are on number 3 out of 10, for example. You have a sense of where you are going.

Sacha: Otherwise, I find I just wrap around to the beginning and I take a moment to reorient myself because it has wrapped around. The other thing that I want to point out related to isearch as well is using it to help you mark a region. This is something that people aren't used to because in other editors, you highlight things with your mouse, right? Here in Emacs, we say, okay, press C-SPC to say you're going to start a region, and then just search for the end of the region, navigate to it somewhere, and the text between when you press C-SPC and where your cursor is now, that's the region.

Prot: Yes, exactly.

19:26 C-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 you started is up there, it moves the cursor up there and 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 it for expanding the region. I usually just use it to confirm that, yes, I am actually selecting the parts that I meant to select. Because by the time, of course, I've found the thing that I wanted to end the region with, I've forgotten or I'm not entirely sure I have the right start. So I was using C-x C-x to quickly verify and have everything nicely highlighted. But expanding the region, yeah, that's a thing you can do with it.

Prot: Yeah, yeah, of course. Now it's obvious, right? But it's something that you may notice by mistake, by accident.

Sacha: [interrupted by life] @charliemcmackin4859 says, "I love that you can make those marking tricks part of a keyboard macro."

20:55 Popping to marks - going back to where you were

Sacha: Oh, the other thing I want to say with marks is you 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 can search for the key binding. Which basically means for all the places where you were before you went off searching for something else or doing some other command, you can go back to those places in sequence. I think there are even some commands to let you easily navigate through all the places you've been previously. That is a thing that you can do with Emacs built-ins. It's called popping the mark. It lets you revisit places.

Prot: Yeah, yeah. Another point related to this and also related to yank that we said earlier...

21:49 Selecting what you just pasted

Prot: Imagine you have copied something and you are pasting it now in your Emacs. Then what you want to do is select it, maybe to do something with it, such as to make it all up case or whatever, right? Instead of selecting it manually, you can just do C-x C-x. Because when you paste something or when you do I search or whatever, it has 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 easily see what it highlights, the part that you've just pasted, and then you can do your other replacements or uppercasing or whatever else to it.

22:33 Indenting pasted or selected text with indent-rigidly

Prot: The nice part for this is the indent-rigidly, C-x C-i by default, where you can now have a region of text including an implicit region between mark and point, and you just shift it 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 to move things, so you can just nudge it until it looks right, which is great because sometimes, when you paste things, the indentation isn't the same as all of the rest of your stuff. You might want to put it all the way into an Org list or whatever else, code block, whatever.

Prot: Okay.

Sacha: So C-x C-x, very handy even after you paste.

23:24 Popping to mark after xref or imenu

Sacha: Oh, @hmelman also points out 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. In general, if you have navigated away from something using some magical Emacs command that has taken you far from where you are, you can always find your way back home or back to where you were by popping the mark. I think there's even a distinction between popping the mark in your buffer versus popping your global mark. You can go to a different buffer that you were just in if you wanted to.

24:05 Adding other packages like consult

Prot: Very nice. Many of these are also augmented by packages. When you install a package, it doesn't introduce completely new functionality. It adds to existing one. For example, the consult package, which is very useful, very nice, has something to do 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 global marks are useful to navigate through. Check out all these other packages for adding extra functionality around that.

24:44 Tip about indicating isearch wrapping

Sacha: @matthewjorgensen9115 says, "thinking about isearch wrapping around search, gwhen you get to the bottom of your file, when you're isearching and there's no other matches to be found, it will by default wrap you around to the beginning of the file so you can keep searching from there." Matthew says you can either have scroll to position to know the direction (it also indicates the position in your mode line), or you can have your mode line flash to see it move from last to first. I don't have that configured. I should look into how to get that configured because it's like all these little things, right? But sometimes you don't need to make a big navigational jump. You just need to move forward by a little bit.

25:26 Navigating by sentence or s-expression

Sacha: Emacs has built-in shortcuts for navigating by expression, maybe things inside the parentheses or things inside the quotes, as well as natural language shortcuts like navigating by word or by sentence. Those are some very useful built-ins that are well worth learning the keyboard shortcuts for.

Prot: Yes, indeed. Of course, we call them S-expressions and the terminology of the commands alludes to Lisp, but they work in other programming languages as well. For example, there is the forward-sexp, but it works in other languages which don't have this Lispy syntax.

Sacha: So if you skipped over that part of the tutorial or the manual, go back and read it because it can save you some time. In a pinch, it will also help you make sure that your parentheses are matched up correctly and you go to where you expect them to go. There are other ways to make it easier to match up parentheses or braces or brackets or quotes like [ show-paren-mode ] or whatever. Sometimes I just go forward and back to see whether 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 adding an extra parenthesis, and it says "end of file during parsing", or one less parenthesis, what you can do with a combination of keyboard macros... You go to the beginning and 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, if you give the execute-kbd-macro a negative argument, it'll run until error. So you just do that and 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 a narrowed region as well. Error here means end of region, end of buffer.

Sacha: I should point out in the specific case where you're trying to hunt down a stray parenthesis, you should also just use check-parens, which will tell you.

Prot: Of course.

27:45 Navigating to other errors

Sacha: And for other errors not just limited to missing quotation marks or parentheses, it's well worth taking the time to set up flycheck or flymake or whatever error checking thing you want to use, because then you can navigate to the previous and next errors as easily as you would with keyboard shortcuts. If you get the hang of doing that, you can also use the same mental model to navigate through... If you're doing a keyword search with grep, then you can use the next-error, previous-error to also go to just the next match or the previous match.

Prot: That's very useful.

28:29 Tags

Sacha: I am not using tags nearly as much as I probably should for navigating symbols.

Prot: Tags, yeah, in the context of programming. Me, I haven't used that, no.

Sacha: Oh, yeah? I guess because you primarily work with Emacs Lisp, it's easy enough to find the definition from there.

28:47 Imenu

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, of course, it's with completion. Now, I should say here, of course, that the default imenu has this concept of going in steps, but you can flatten the list, which is more interesting for the purpose of completion. I believe what I'm saying is the case, but I don't remember anymore. But you can have a flattened list, at which point you navigate the file with completion.

Sacha: I should try that because I really like the way that Org, when you're navigating by the outline, you can also configure it to flatten the list so you don't have to complete the heading and the next setting and all that stuff. @hmelman says you don't actually need flymake for the error navigation thing. You can just use next-error and previous-error which works with compile and grep and occur and a bunch of other things that have the same convention. So yes, if you use the M-x compile command to run whatever your compilation step is, it will parse the output of many compilation systems, programs, and it will let you jump to the next error. 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:19 Projects

Sacha: I think projects and project-based navigation is another big chunk of Emacs built-in functionality that is useful for people who have a 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 want to go to this project. Then from within this project, I can find a file very easily.

Prot: This is indeed very powerful. The thing is you don't have to also think in terms of the structure of the project, like the tree structure of the project, because if you find the file in the project, it will flatten the structure for you, so then you use completion to find it or find the directory where something is. Of course, you can still use the tree view as well.

Sacha: This is great because for example, in Java projects, the directory structure gets very deep because they have to be their domain name and package names and all that stuff. Just have either project or projectile index all of your files for you, and then you can jump to a file 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 into your node-modules. That would be silly.

Prot: Yeah, that would be a nightmare.

Sacha: Do we have basically the Emacs built-ins for finding your way around well covered here, or other other recommendations that people 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 you can do more stuff with them.

32:10 Putting projects in tabs or frames

Prot: For example, with projects, you may want to have an arrangement where you put them in separate tabs, and then you use a package like tabspaces so that each tab has its own buffer list, or my package beframe so that you put them in separate 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:35 Tabs

Sacha: I am not using tabs nearly as much as I probably could, so that is one of my underappreciated Emacs built-ins here. I'm getting the sense that people use tabs to say, okay, this is the set of windows related to managing my mail, or this is a set of tabs related to this project. This is a set of windows related to this project, or this is a set of windows related to managing my notes about something. Is that what you use tabs for?

Prot: I seldom use them. I use them specifically only within the context of 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 and just go into Magit to do some Git operation. I configure display-buffer-alist so 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 a good advocate of checking out display-buffer-alist and all the wonderful things it can do. I should definitely look into having it set up a tab because that sounds a lot nicer than trying to remember, okay, I need to save my window configuration to register and then do this thing. I have it set up actually so that I can winner-undo in order to get back to my previous configuration. But of course, if I need to flip back and forth between two different views, like Magit and my project code, then a tab would work much better 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 little annoying too.

Prot: Of course, of course. There are pros and cons.

34:41 Navigating frames

Prot: Speaking of frames, one nice thing is that there is 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 know where 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 name rather than it changing the name all the time. So you can say, OK, this is my super important 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 most part, I have a keyboard shortcut like Super 1 which jumps back to Emacs, raises my Emacs window. But it doesn't work so well if I have multiple Emacs window, like multiple Emacs frames. If I can figure out how to get mentally through that or if I switch to EXWM as my window manager, then I'm sure that managing multiple Emacs frames will be a lot easier. But at least tabs, I can probably use within that one frame in order to manage different windows.

Prot: I would say tabs is the first thing you want to check. Frames is a little bit more... You have to change your mental model a little bit.

36:07 These navigation shortcuts work for prose, too

Sacha: @hmelman has one more tip to include in this section on finding your way around. You can use these S-expression commands in prose too. Like for example, C-M-u or backwards-up-list moves you out of a quote or a parenthesis and 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 to get 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 then go to the end of the quote. Also very handy to learn the commands for killing an S expression [ kill-sexp ], which again also works with other stuff like quotes or parentheses, because then you can copy and paste things or you can kill it. You don't have to paste it back. It's just you delete it and then you type something else in. It's fine.

Prot: Exactly, exactly. And one of those is the mark-sexp, which is very useful.

37:09 follow-mode

Sacha: Oh yeah, oh yeah. And @matthewjorgensen9115 shares: follow-mode allows the same file with multiple frames like a book. So follow mode can work with two, three or more windows. You have an ultra wide, right? So like, okay, you can have several columns following the same file and you can scroll and all of them will scroll in sync.

Prot: Yeah, yeah. It's quite nice. Quite nice.

Sacha: I forget, does follow mode work with 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:50 Ediff

Sacha: If you do find yourself needing to compare one file with another manually, then maybe like ediff?

Prot: Ediff would do that. You would have them side by side. But the thing with Ediff is that you don't get a scroll lock for both. It's only navigation through the differences. So that wouldn't be exactly that.

Sacha: For the purposes of comparing, Ediff will let you compare two files, but you can even use it to compare two buffers. However, Prot does have some recommendations in the one on the defaults that you shared before on how to make Ediff more manageable.

Prot: Yeah, I think by default it's not intuitive, because by default, when you do Ediff without any configuration, it will display its panel in a separate frame. If you have never used many frames, that's already your first problem. Like you don't even know what happened. The second problem is that the layout will be one above the other, which depending on your screen, you have like a wide screen, so it's not as easy of a layout. Then you have to figure out where the other frame with the panel is. Basically two variables where you change them and you have the panel at the bottom, the control panel and then file A here, file B there. And of course you can do it with three files as well.

Sacha: I will find it and put it in the show notes. Matthew also points out the following also works with centered-cursor-mode [(it’s a package)], which will keep the cursor position in the middle of the frame. So I can't remember whether there's also like a scroll lock or whatever.

Prot: scroll-lock-mode. Yeah, there is `scroll-lock mode.

Sacha: Or there was another Emacs built-in that someone mentioned that scrolls it one line at a time, keeping it centered, I guess, which the person found very useful because their cat was sitting on their laptop. So moral lesson is: learn about the Emacs built-in because you never know when a small mammal will be obscuring half of your screen. You can still use Emacs. Which actually is an interesting segue into this thing about discoverability because Emacs is quite unlike many other editors. It is very well documented and if you can figure out how to navigate and find that documentation and even how to make this fun for you, then you can do all sorts of interesting things with it. Okay, so self-documentation. I love telling people, okay, you can just press C-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 the keyboard shortcut that you've started but you've forgotten how to finish, especially if you've turned on which-key mode, is great for listing the actual shortcuts that start with that sequence.

Prot: And even without which-key, it will put all those shortcuts in a Help buffer, and it will show the key and the name of the command. Of course, you can click on the command to read about it.

Sacha: Someday I think it would be amazing if Emacs comes with a completion interface that's easy for people to understand and get started with, but in the meantime, if you don't already have completion set up, that is well worth taking the time to figure out.

Prot: Yeah, yeah. The built-in one has improved tremendously. I mean minibuffer.el here has improved tremendously over the various recent versions. But you still need to be aware of all the user options to configure it. So to get, for example, a single column view instead of a grid with 100 options... That requires some effort. Out of the box, if you really want something that is built into Emacs and does completion in a way that is fairly easy to understand, it would be icomplete-vertical-mode or fido or fido-vertical-mode.

42:12 Calling functions by name

Sacha: Another thing that Emacs does differently that might be good for people to learn about is that in Emacs, it is totally okay to not remember the keyboard shortcuts for everything or not use the menus for everything, because not everything will fit in the menus either. If you kind of remember the name of the function, you can use M-x and possibly completion to go run that function, which is helpful because sometimes knowing the words to call a function is a lot easier to remember than remembering the shortcut for it.

Prot: Exactly. And I would say completion...

42:52 Completion

Prot: If you have to configure one part of Emacs, it's completion. If you improve that part of it, it will help you everywhere. Like we were saying earlier about bookmarks, it helps 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, also learn how your favorite completion system lets you put in things that look like they should match something on the list, but you actually want just the partial part or just the blank part. For example, in some systems, you press M-RET or M-p to send what you already have there instead of selecting one of the completion options. This is helpful because sometimes you'll want to name a file something that is a substring of another file and you want to be able to say, yeah, that is actually what I meant, not the completion part.

Prot: Yeah, yeah. I think that's the only rough edge with most of those, yeah. Where you have to be mindful of that or, you know, I have to select the prompt or I have to type a special key for this edge case. Yeah.

Sacha: Once you get that sorted out and you've drilled it into your fingers, it's very, very helpful to have completion sorted out.

44:13 Manuals

Sacha: Emacs also comes with extensive manuals. You like to write very thorough manuals for your packages, which I also appreciate. Flipping through manuals for fun is something that we've discussed in previous... This is such a great practice. You learn something new every day. I was going through the Emacs manual in preparation for this conversation and I was just highlighting things that I need to dig into.

Prot: It's very useful and again to point out completion. C-h R is how you can search for the manual 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 for something else, right? Elisp, for example, to go to the Emacs Lisp reference manual. Again, very useful. From inside the manuals, g to go to a chapter, also known as a node, i to go to a topic, 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 the current node.

Sacha: I use s also for search.

Prot: And there's for research throughout, yes.

Sacha: Yes. I have not been using C-h R. I have been using C-h i to look at the whole list of info manuals and then using m or isearch like a newbie.

Prot: That works. The problem with that is that if you have already gone 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:57 Menus

Sacha: Okay, you mentioned you are not a fan of... you don't use the menus and I know a lot of people...

Prot: But I appreciate that. And in one of my... oh, in a couple of my packages I have menu entry.

Sacha: Yeah, and I know a lot of people turn the menu bar off in their "this is how you configure Emacs" sort of tutorials. But if you are new to Emacs, and even if you're an intermediate user, I strongly recommend, sacrificing that tiny sliver of vertical space for the menu bar, because it's a great way to discover commands that are related to your particular major mode or other things. It's just fun to go through it and see what's been deemed worthy of including in one of those menus. There are some efforts now to get the right-click mouse menus to also have lots of interesting options, but definitely the menu bar at the top, which can also be accessed if you use F10 if you don'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 useful suggestions 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 use the mouse. There you have it. You don't have...

Sacha: And speaking of key navigation, if you press C-h k, which is describe-key, it will work on menu items as well. If you're finding yourself always going to the menu to do this thing, sometimes the menu items are not named the same as their commands, but you can use C-h k to find out what that function is and what keyboard shortcuts it's bound to. Then you can call it with M-x directly, or you can memorize the keyboard shortcuts.

47:46 Automation - 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 is actually something I picked up from reading your config, 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, my fancy French expressions, like, this is so déjà vu, you know? I want to have the accents correct. I just write deja vu with English, and then I have the French equivalent with all the fancy accents. Stuff like that you can do, like... something you keep misspelling the whole time you actually do it, right, something that is with an annoying spelling, like annoying capitalization like LaTeX. Nobody knows how that is written. You just write it latex, all lowercase, and then expand to whatever it should expand. This sort of thing is very useful. Of course, you can just have some short text which expands into very long text.

Sacha: We should also point out if you type something that is normally an abbreviation like LaTeX, but in this case you actually want to write the word latex, then how do you do the abbreviation without it being expanded into whatever that is?

Prot: Of course you would rather avoid that situation with your abbreviation. It wouldn't be 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 I would say, just make sure to have abbreviations that are not ordinary words. They are a little bit contrived, so you don't get false positives. A good use case here, like what I have in my configuration, like you can have your abbreviations behind a character such as the semicolon. Then of course it's very unlikely that you will have semicolon later.

49:56 Quoting the next character with C-q

Sacha: The other thing that you could potentially do is use C-q to quote the next character literally. So here for example, I have ot expand to the current time, but if I say ot C-q SPC, this helps. And in general, this idea of C-q to quote the next character is also useful in other places where you might, for example, need to add a literal new line to a search or something like that, or a literal tab.

50:31 Mapping abbreviations to code

Sacha: The other thing that I want to add to abbreviations here is your abbreviations are not limited to just text. You can use them to run things, which means you can use them to run things that expand to text, or I think you might even get away with using them to run commands. So it's pretty limitless.

Prot: Yeah, yeah. Of course, it's how determined you are to write custom code for that.

Sacha: Or how resourceful you are in finding other people's custom code that you can copy, 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 that basically everybody uses. Yasnippet or Tempel.

Sacha: A couple of questions from chat. When highlighting parts of the manual, how are you 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 one of those graphical note-taking things and I was highlighting with the Pencil. But I've heard good things about Org Remark, which is a package.

51:51 Taking notes with org-capture

Sacha: You can also use just org-capture if you’re reading the manuals from within Emacs, which you can. If you org-capture, you can even select sections of the manual and it'll automatically save that in the capture template along with a link back to where you were looking. This is great.

52:08 Navigating back to captures or refiles

Prot: Since you mentioned org-capture and we talked about bookmarks earlier, when you do org-capture or org-refile, it stores a bookmark. You can go back to the last capture, the last refile.

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 last thing 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 your projects, for example, or any of your notes, assuming you’ve set up your org-refile-targets appropriately. Okay, @RandCode has question. Does Emacs have a grammar checker like Harper's LSP? I know there are packages that people can use to work with Harper and other things. Do you know of any other built-in things?

Prot: Built-in, it's flyspell, but that'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 into Flymake.

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, over icomplete. So it's vertico, and then with that, I would say, at minimum, orderless. So vertico and orderless, at minimum. But then, of course, if you want a little bit more, 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:49 dabbrev

Sacha: @hmelman says dabbrev for dynamic abbreviations is underrated. You don't need to predefine them. You just type the start of a word or symbol and type M-/, and it will search the buffer for something starting with what's on the left side of 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 try words from other buffers or other things that you've got or contacts or whatever. Anyway, so dynamic abbreviations. If you search for dabbrev and if you look also for hippie-expand, you will find lots of things that you can configure to fit your particular workflow. So you can expand abbreviations without having to define them.

Prot: Yeah, yeah, yeah. Super powerful. Super useful. I use it more than tab completion, you know, like with core. I use dabbrev more. It's very nice. Yeah.

54:44 Keyboard macros

Sacha: Okay, so we've mentioned keyboard macros very briefly, but this is another very powerful chunk of things that people might not be used to if they're coming from an editor that is not Emacs. So keyboard macros, what's kind of like the thing that we can use to explain? How do we explain it to people who are new to this?

Prot: In its simplest form, you record what you type and you can play it back in its simplest form. But the thing with Emacs is that you don't just record typing motions, typing actions. You also record all the Emacs motions. You can have a keyboard macro that includes stuff such as move to another window or create a new split or whatever. You can do more advanced things like that. This has very nice qualities to it where it's like, oh, I just want to copy all these symbols and move them to my shell buffer and then I will do something with them, pipe it to something like a program outside of Emacs. So it has a lot of nice applications like that.

Sacha: I think that if people can get the hang of: very carefully set up their keyboard macro, think what's a series of steps that I can do so that I can do the change and then move my cursor to the start of where the next change should be... For example, I'll start the keyboard macro, I'll delete the word, I'll type in something new, or maybe I'll paste in a register I'll use isearch to find the next point at which I need to do something. If you define your keyboard macros like this, then you're giving yourself the ability to interactively confirm whether you're still on the right track and then make the change because that way, it's not just like a search and replace and you're hoping it all works out. Although the recent search and replaces are great because they show you the changes. But for something that's more complex, especially if you're not used to regular expressions, keyboard macros can help you interactively do it in small steps.

Prot: Yeah, exactly. Of course, search and replace will be more tricky if you have to go through many files and perform multiple edits in each, because then the concept of regular expressions breaks down. You don't want to think in those terms where it's like, I will have to make a change somewhere towards the top and then somewhere in the middle and then somewhere towards the end. Keyboard macros combined with Dired combined with going to file... Very nice. Just to say another thing about keyboard macros is... Let's say you have written your very nice keyboard macro. You're recording it, and somewhere towards the end, you make a small mistake. Keep going and then C-x C-k C-e to edit your macro. It's a text buffer. You just remove what you don't want.

Sacha: You can save these keyboard macros as well. You can use them in a future Emacs session or even turn them into your first Emacs Lisp function. You can give it a name and you can run it that way.

57:52 Editable grep and occur

Sacha: In the next three minutes before the kiddo runs out for lunch break, I also want to mention, since we talked about making changes in multiple files, that grep and occur are both editable. You can do your grep and you can search for things. And then you can say C-x C-q which turns it from read-only to something you can change, then you can do your search and replace in that, and you can C-x C-q again and those changes can get put back into all those different files.

Prot: It's amazing. On this note, specifically for grep, if you edit many files with the grep edit mode that is built 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 can type d to see the diff. Like, okay, what exactly did I change? If you have many unsaved files, d to see what you're about to save so you never make any mistakes.

Sacha: Mm-hmm. Taking advantage of these diffing tools is great also. Even if you're new to Emacs or you don't have a programming background, if you find yourself making changes to lots of files, I strongly recommend learning more about version control systems like Git and then using something like Magit or even the built-in VC. If you use VC, you can use it and you have set up something like a git repository. You can use `C-x v =` to diff to see the changes between your file and the previous thing that you had saved. Which makes sense so that you can see, okay, these are the changes. Also it means that you can experiment with different changes. You can experiment with different ways of writing a paragraph or whatever, and you know that all of your previous versions are saved and you don't have "really, really final version two." You don't clutter your directory with a lot of copies of the same file.

Prot: But even if you don't have any of the version control system set up, a very simple thing is diff-buffer-with-file. So you have a file you are working on and now you make some edits. The buffer, what is in memory, is different than what is on disk. You can compare the difference between the two.

Sacha: Okay, I'm going to try to wrap up here because the kid is going to run and say hi very soon. Thank you so much for joining me. Of course, there's a lot more to talk about the Emacs built-ins, but I hope we've given a quick tour of some of the things that are definitely worth learning more about and the situations for which they are absurdly useful. Thanks to everyone in chat also for coming and hanging out. I will post the show notes eventually and get the transcripts 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:01 Emacs Carnival June 2026: Underappreciated built-ins

Sacha: Also, if folks are interested, even if you've never blogged before, the Emacs carnival theme for June 2026 is "Underappreciated Emacs built-ins," which is why we had this conversation. Feel free to write about something and either send [Ross and] me a link, or you can even send me the post and I'll post it on my blog with your name on it and other things like that so you can share your appreciation for these built-ins. All right. Okay, I hear movement. I gotta go. All right.

Prot: Take care, Sacha. Take care, folks. Goodbye.

Chat

  • 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!!!
View Org source for this post

You can e-mail me at sacha@sachachua.com.

-1:-- Yay Emacs 33: Sacha and Prot Talk Emacs: Built-ins (Post Sacha Chua)--L0--C0--2026-06-09T02:51:39.000Z

Protesilaos: Emacs live with Sacha Chua about ‘Underappreciated Built-ins’ on Thursday 11 June 17:30 Europe/Athens

Raw link: https://www.youtube.com/watch?v=yuJYEua0ZwA

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!

The video will be recorded for future reference.

-1:-- Emacs live with Sacha Chua about ‘Underappreciated Built-ins’ on Thursday 11 June 17:30 Europe/Athens (Post Protesilaos)--L0--C0--2026-06-09T00:00:00.000Z

Sacha Chua: 2026-06-08 Emacs news

It's Emacs Built-ins appreciation month! I'm coming to appreciate the menu bar more. What built-ins do you appreciate? Write about it and send Ross a link!

Links from reddit.com/r/emacs, r/orgmode, r/spacemacs, Mastodon #emacs, Bluesky #emacs, Hacker News, lobste.rs, programming.dev, lemmy.world, lemmy.ml, planet.emacslife.com, YouTube, the Emacs NEWS file, Emacs Calendar, and emacs-devel. Thanks to Andrés Ramírez for emacs-devel links. Do you have an Emacs-related link or announcement? Please e-mail me at sacha@sachachua.com. Thank you!

View Org source for this post

You can comment on Mastodon or e-mail me at sacha@sachachua.com.

-1:-- 2026-06-08 Emacs news (Post Sacha Chua)--L0--C0--2026-06-08T18:36:11.000Z

Raymond Zeitler: Emacs and the Numeric Keypad

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:

(keymap-local-set "<kp-0>" #'(lambda () (interactive) (insert "zero")))

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.


https://en.wikipedia.org/wiki/Numeric_keypad
-1:-- Emacs and the Numeric Keypad (Post Raymond Zeitler)--L0--C0--2026-06-08T15:51:22.851Z

Irreal: Elfeed 4.0.0

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.

-1:-- Elfeed 4.0.0 (Post Irreal)--L0--C0--2026-06-08T14:46:14.000Z

Charlie Holland: svg-line: Better Status Bars for Emacs

1. TLDR

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.

svg-line-annotated.png

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:

  1. It can be any height. Multi-row bars are now possible in every *-line.
  2. Everything is placed at exact pixel coordinates. Left, right, and center alignment work identically on every row.
  3. 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.
  4. 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.

(svg-line-define 'my-mode-line
  :target 'mode-line
  :content (lambda ()
             ;; one row: (LEFT-SEGMENTS . RIGHT-SEGMENTS)
             (list (cons (list (buffer-name))
                         (list (format-mode-line "%l:%c"))))))

(svg-line-activate 'my-mode-line)

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.
(defun my/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.

(svg-line-define 'my-tab-line
  :target  'tab-line
  :layout  'wrap
  :content (lambda ()
             ;; each item is (LABEL . STATE)
             (mapcar (lambda (buf)
                       (cons (buffer-name buf)
                             (list :current  (eq buf (current-buffer))
                                   :modified (buffer-modified-p buf))))
                     (tab-line-tabs-window-buffers)))
  :current-background  (lambda () (face-background 'highlight nil t))
  :modified-foreground "#ebcb8b")

(svg-line-activate 'my-tab-line)
  • :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.

-1:-- svg-line: Better Status Bars for Emacs (Post Charlie Holland)--L0--C0--2026-06-08T11:58:29.000Z

Sacha Chua: June 18: Emacs Chat with Ross A. Baker

On June 18, I'll chat with Ross Baker about Emacs and life.

America/Toronto = Thu Jun 18 1030H EDT / 0930H CDT / 0830H MDT / 0730H PDT / 1430H UTC / 1630H CEST / 1730H EEST / 2000H IST / 2230H +08 / 2330H JST

This session will be recorded, and I'll update this blog post with notes. https://sachachua.com/blog/2026/06/emacs-chat-with-ross-a-baker/

Find more Emacs Chats or join the fun: https://sachachua.com/emacs-chat

View Org source for this post

You can e-mail me at sacha@sachachua.com.

-1:-- June 18: Emacs Chat with Ross A. Baker (Post Sacha Chua)--L0--C0--2026-06-07T18:28:45.000Z

Irreal: Correcting The Orientation of macOS Photos on Linux

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.

That leads to the problem: when iPhone portrait mode photos are shown on Linux using Org mode they are shown in landscape mode. You can get the details from JTR’s post.

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.

-1:-- Correcting The Orientation of macOS Photos on Linux (Post Irreal)--L0--C0--2026-06-07T14:12:28.000Z

Bicycle for Your Mind: Much Ado About Emacs 014

EmacsEmacs

Org-Mode and the Capture System

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-captureOrg-capture

You get this.

Journal EntryJournal 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.

My setup for the journal capture looks like this:

("j" "journal" entry (file+datetree "~/Dropbox/org/diary2026.org")
"* %<%R: >\n%? \n" :empty-lines-before 1)

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:

BookmarkBookmark

I came up with a capture template:

          ("b" "Bookmark" entry
           (file+headline "~/Dropbox/org/bookmark.org" "Bookmark")
           ,(concat "* %^{Title}\n")
           :empty-lines-after 1)

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-captureOrg-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 ChoicesBookmark 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.

;; org-capture
(use-package org-capture
  :ensure nil
  :bind ("C-c c" . org-capture)
  :config
  (setq org-capture-templates
        `(("b" "Bookmark Templates")
          ("bc" "Computer" entry
           (file+headline "~/Dropbox/org/bookmark.org" "Computer")
           "** %?"
           :empty-lines-after 1)
          ("be" "Emacs" entry
           (file+headline "~/Dropbox/org/bookmark.org" "Emacs")
           "** %?"
           :empty-lines-after 1)
          ("bm" "Misc" entry
           (file+headline "~/Dropbox/org/bookmark.org" "Misc")
           "** %?"
           :empty-lines-after 1)
          ("bp" "Politics" entry
           (file+headline "~/Dropbox/org/bookmark.org" "Politics")
           "** %?"
           :empty-lines-after 1)
          ("br" "Religion" entry
           (file+headline "~/Dropbox/org/bookmark.org" "Religion")
           "** %?"
           :empty-lines-after 1)
          ("bs" "Shop" entry
           (file+headline "~/Dropbox/org/bookmark.org" "Shop")
           "** %?"
           :empty-lines-after 1)
          ("bw" "Writing" entry
           (file+headline "~/Dropbox/org/bookmark.org" "Writing")
           "** %?"
           :empty-lines-after 1)

          ("j" "journal" entry (file+datetree "~/Dropbox/org/diary2026.org")
           "* %<%R: >\n%? \n" :empty-lines-before 1))))

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.

(use-package org
  :bind (:map org-mode-map
              ("M-s-i" . my/org-insert-child-headline)
              ("M-s-s" . my/org-insert-sibling-headline)
              ("M-s-o" . my/org-insert-promoted-headline)
              ("C-s-<right>" . org-metaright)
              ("C-s-<left>" . org-metaleft)
              ("C-s-<up>" . org-metaup)
              ("C-s-<down>" . org-metadown))
  :config
  ;; Optional: Unbind originals
  (define-key org-mode-map (kbd "M-<right>") nil)
  (define-key org-mode-map (kbd "M-<left>") nil)
  (define-key org-mode-map (kbd "M-<up>") nil)
  (define-key org-mode-map (kbd "M-<down>") nil))

This is all I have for today.

macosxguru at the gmail thingie.

Update: Howard Melman improved the unbinding code with this alternative:

  (keymap-unset org-mode-map "M-<right>")
  (keymap-unset org-mode-map "M-<left>")

Note: I had help from Ollama with the code.

-1:-- Much Ado About Emacs 014 (Post Bicycle for Your Mind)--L0--C0--2026-06-07T07:00:00.000Z

Sacha Chua: Emacs PDF View: Replace current page with file using PDFtk

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
(defun sacha-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)))
This is part of my Emacs configuration.
View Org source for this post

You can e-mail me at sacha@sachachua.com.

-1:-- Emacs PDF View: Replace current page with file using PDFtk (Post Sacha Chua)--L0--C0--2026-06-07T00:35:27.000Z

Raymond Zeitler: Follow-on to exeln

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:

(shell-command (concat
                (buffer-substring
                 (line-beginning-position) (line-end-position))
                (when arg "&")))

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.

(defun exeln (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!


1 https://site.sebasmonia.com/
2 exeln-execute-line.html
3 GNU Emacs online shell-command help
-1:-- Follow-on to exeln (Post Raymond Zeitler)--L0--C0--2026-06-06T23:41:48.603Z

Irreal: Emacs 31.0.90 Pretest

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.

-1:-- Emacs 31.0.90 Pretest (Post Irreal)--L0--C0--2026-06-06T14:42:58.000Z

Marcin Borkowski: Copying images in Emacs

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.
-1:-- Copying images in Emacs (Post Marcin Borkowski)--L0--C0--2026-06-06T04:54:01.000Z

Dave Pearson: blogmore.el v4.6.0

After adding floating and inline tables of contents in BlogMore the other day, it was time to update blogmore.el to include commands to toggle the related frontmatter.

So, with the release of blogmore.el v4.6.0, two new commands are now available:

  • blogmore-toggle-show-toc toggles the show_toc frontmatter property.
  • blogmore-toggle-show-toc-inline toggles the show_toc_inline frontmatter property.

Both have also been added to the transient menu so they're easy to discover and use.

-1:-- blogmore.el v4.6.0 (Post Dave Pearson)--L0--C0--2026-06-05T19:01:30.000Z

Lars Ingebrigtsen: Super Simple Spam Splitting for Gnus

Spam is an eternal problem, and while SpamAssassin is pretty good (I get around 700 mails per day, of which 670 are rejected as spam), there’s still some stuff that persistently gets through. A goodly portion of that is traditional random spam from random accounts, and there’s not much to be done about that, but there’s a recent trend of legitimate-looking things coming from persistent accounts — like BackerHome and BackerHive.

I’m guessing that eventually these will get so bad reputations that they end up on RBLs and will disappear into the mists, but meanwhile… I just thought that there should be a mechanism in Gnus to split these message to the spam group — without having to do much work.

Tada!

It’s a small package, and you can find it on Microsoft Github. It’s basically a tiny minor mode that adds a couple of commands, so you just hit z, check the entry (or not) and then C-c C-c.

(There’s also a command to edit the split data if things go off the rails, or just because you want to.)

B t to check the split trace, as normal.

So there you go. May your inboxes be slightly less spammy.

(And it’s fun doing some Gnus work again for the first time in years… I’ve forgotten what all the functions are called, though, so I had to use Claude to remind me. *gulp*)

-1:-- Super Simple Spam Splitting for Gnus (Post Lars Ingebrigtsen)--L0--C0--2026-06-05T11:44:55.000Z

Raymond Zeitler: exeln: EXEcute LiNe

The following exeln function passes the current line to the system shell, which executes it, thus EXEcuting LiNe.

On Windows x86, my GNU Emacs has shell-file-name set to cmdproxy.exe, which is provided by x86_64-w64-mingw32, with which Emacs was compiled.

shell is invoked synchronously by default; a prefix argument can change this to asynchronous.

In the video below, point is on a line of text that would print the contents of hello_whirled.txt when entered at the Windows command prompt (or DOS prompt). I press C-c x, which is bound to exeln. The command is executed and the output is shown in *Shell Command Output*, the default buffer used for synchronous output from shell-command.

(defun exeln (arg)
    "Execute the current line as a shell command.
With prefix arg, operate asynchronously, same as calling
(shell-command COMMAND) where COMMAND ends in '&'.
Otherwise, execute synchronously."
  (interactive "P")
  (let (asynch)
    (if arg
        (setq asynch "&"))
    (shell-command (concat
                    (buffer-substring
                     (line-beginning-position) (line-end-position))
                    asynch))))

2026-06-04 Add demo video

-1:-- exeln: EXEcute LiNe (Post Raymond Zeitler)--L0--C0--2026-06-04T17:53:49.163Z

Charles Choi: Revisiting Emacs Keyboard Macros with a Mouse

“No-code automation” has been in Emacs far longer than its usage as a term of art. Better known as keyboard macros, this feature has allowed Emacs users to achieve their bespoke needs for decades, all without needing to know a whit about Lisp. I can testify to this personally: though I’ve been using Emacs since the early 90’s, only in the past three years has writing Elisp played any part in it. For most of my Emacs journey, I got by with just making keyboard macros.

If you’re unfamiliar with them, here are two links you should get to know:

My addition to the knowledge of those posts is to boost this fact: mouse events can also be captured by a keyboard macro. If you know where a command is in a menu, you can also record clicking on it. I think the ability to combine both keyboard and mouse events in a keyboard macro is compelling, so much so that I decided to emphasize this in Anju.

The recent Anju v1.5.0 release added the menu “Tools › Macro Recorder” to the menu bar as shown below.

img

With this, mouse enthusiasts can create and run keyboard macros without need to recall keybindings or deal with inconsistent command naming, as observed in Petersen’s post.

One thing that I TILed about keyboard macros in building this menu was the command list-keyboard-macros (see (emacs) Kmacro menu). This command is available in the “Macro Recorder” menu as the item “List macros”. This lets you manage multiple keyboard macros that have been defined during a session.

If this interests you, I invite you install Anju from MELPA and give it a try. Let me know what you think!

-1:-- Revisiting Emacs Keyboard Macros with a Mouse (Post Charles Choi)--L0--C0--2026-06-04T16:35:00.000Z

Irreal: Inhibit The Mouse In Emacs

James Cherti has a new version (Release 1.0.4) of his inhibit-mouse package available. As the name suggests, it disables the mouse while you’re using Emacs. I’ve written about inhibit-mouse before. As I said in my previous post my first thought was that I don’t need this because I’ve already trained myself not to use the mouse while I’m in Emacs.

The thing is, though, that I mainly use my laptop—a MacBook Pro—which has a trackpad for mouse operations. Since I often use my laptop on my lap while sitting on the couch, it’s easy to inadvertently touch the trackpad with my palm and change focus from one window to another. Turning off the mouse would eliminate that from happening. Still, I do use my trackpad to scroll Web pages and emails that are displayed with WebKit because there’s no other decent way of doing so. Happily, inhibit-mouse is very configurable and you can, in particular, disable it’s use in any major modes you like. That may solve my WebKit problem.

Inhibit-mouse is a reimagining of Steve Purcell’s disable-mouse package. Cherti claims inhibit-mouse has some advantages—such as being more efficient—over disable-mouse. Take a look at the repository to see what they are.

If you’re looking for a way to banish the mouse from your Emacs experience, this seems like a good way of doing so. You can even leave a couple of escape hatches if you need to.

-1:-- Inhibit The Mouse In Emacs (Post Irreal)--L0--C0--2026-06-04T15:20:56.000Z

Sacha Chua: Emacs Chat 25: Ben Zanin (@gnomon@mastodon.social)

: Updated the transcript

I chatted with Ben Zanin about music, Org Mode, Emacs in terminals and on an Android, keyboards, elfeed, and more.

View in the Internet Archive, watch or comment on YouTube, read the transcript online, download the transcript, or e-mail me.

Chapters

  • 0:00 How Ben got started with Emacs
  • 2:19 Ben got into Emacs because of twittering-mode
  • 4:30 Emacs as a media playback platform with Versuri and Mpdel
  • 9:13 Emacs on Android with Termux
  • 13:44 Keyboards and other devices
  • 16:44 Benefits of a split keyboard
  • 18:22 Meeting workflow
  • 21:11 Narrowing
  • 22:58 There's even an internal Slack channel about Emacs at Ben's company
  • 24:50 Ben keeps Org capture templates as individual files and adapts them to different meeting flows
  • 28:45 Personal-scale software and the journey
  • 34:07 vc-git-grep for finding notes again
  • 36:55 Add keywords to make things easier to find again
  • 37:47 Keybindings and terminals; wezterm
  • 42:38 Timers: tea-timer, tmr
  • 43:57 Different stages of package use
  • 44:47 Elfeed
  • 48:36 Spoilers
  • 49:53 Comparing different news sources
  • 53:13 Bookmark naming conventions
  • 53:24 Naming conventions simplify building new workflows
  • 53:50 elfeed-curate for annotations
  • 55:46 mytoots archives Mastodon toots
  • 57:06 Mentoring offer
  • 58:02 A local instance of public-inbox can let you use Gnus to read mailing lists quickly

Transcript

Expand this to read the transcript

0:00 How Ben got started with Emacs

Sacha: I forgot to ask you how your last name is pronounced.

Ben: Oh, Zanin.

Sacha: This is Emacs chat number 25 and here I am with Ben Zanin. You have a math background and now you're in IT. Where did you encounter Emacs in the journey?

Ben: So the reason I have a math background is that I wanted to get into programming language design and at the time so that led me over to lambda calculus and that kind of thing and at the time it was at the time I was getting into university in like 2005-2006 It was impossible to get into the computer programs, but I could get into math. I figured that would move me in the direction that I wanted to go in, so I did. Got to third year, and then every professor who taught any of the courses I cared about all left the faculty at the same time.

Sacha: Oh no!

Ben: Yeah. Anyhow, that's a different story. But yeah, I got into Emacs because in the process of learning about Lambda Calculus, the Lisp weenies found me. And yeah, I spent a bunch of time learning about that. And it wasn't until like 10 years after I got into Common Lisp and Scheme that I actually got into Emacs at all.

Sacha: That's interesting. Usually people, like, if they're doing Lispy things, they get into Emacs right away because Lisp. But okay, so 10 years after. You're already well-used to parentheses at that point.

Ben: Yes. But I guess it wasn't until about ten years ago, like around 2015 or so, that I started really getting into Emacs. I would still consider myself to be a beginner on that front.

Sacha: Oh yeah? So what got you to get into it more?

Ben: I found that I was looking for more structured data management processes. Basically, I was looking for personal information management. And I kept bouncing off Emacs because I wanted to get into those tasks, but Emacs was such a rich learning process that I kept getting sidetracked, so I kept bouncing off of it.

2:19 Ben got into Emacs because of twittering-mode

Ben: But I have to admit that one of the things that originally actually got me into Emacs was twittering mode. Oh yeah? Because I was looking for a tool that would let me, we'll probably get into this later in the chat, but I was looking for a tool that would let me keep a larger window of context about the conversations that I've been in. The Twitter apps and the Twitter website implemented a really narrow window. I wanted to be able to search back a couple of weeks for stuff that I had seen or talked about previously. Twittering-mode gave me the ability to keep days or weeks of context in a single buffer that I could then immediately search. So I didn't actually get into Emacs as a text editor, I got into it as an application platform, and then gradually learned the rest of it. This is actually fantastic. So I kind of stuck around after that.

Sacha: That is the first time I've heard of someone coming to Emacs because of Twitter.

Ben: No, it's deeply embarrassing.

Sacha: No, it's wonderful. I love that there's just so many reasons why people come and the fact that you could find something that would let you take those notes and see that context and reply to it, and even, as I see in your config, work around slow keyboard response issues.

Ben: And also the fact that that's still in the config despite Twitter itself... I think I abandoned it in 2017, but it takes me a little while to rip things out of my config.

Sacha: Yeah, I see you're a lot more active in Mastodon these days. I see your Monsterdon posts scrolled by my feed every so often. Yeah, so we dove right into that because a lot of the stuff in your config is interesting and your workflows too. My idea for these Emacs chats is to show people the kind of stuff that isn't immediately obvious to newbies when they're looking at someone's config. Because a lot of the stuff is new workflows and how the keyboard shortcuts work together and how this stuff fits into your life. That's not immediately obvious from the code. I've taken a look at your config, but before we jump into the gazillion things I wanted to ask you about, are there things that you particularly love about your Emacs workflow?

4:30 Emacs as a media playback platform with Versuri and Mpdel

image from video 00:07:24.567Ben: I'm probably going to get a little bit of deserved flak for this, but I use Emacs a lot as a media playback platform. I spend a lot of time using Emacs to listen to music through MPV. And I've got some integration with Versuri, which lets me... I think you've seen those customizations where what I've done is I've kind of duct-taped the two together. Versuri is an Emacs package for being able to quickly search through lyrics for songs. What I've done is I've bound Versuri to the point where I've pulled up a page of lyrics, I now have a hotkey that bounces me over to a search of my MPD library for where that song is, and vice versa. I've got MPD rigged up so that when I've got a song currently playing, I can bounce into Verisuri to display the lyrics for that particular song. Something you probably have not seen in my config yet because I haven't finished it yet... What I'm working on is actually integrating Org Mode with MPD, because I'd really like to be able to streamline my process where occasionally when I'm listening to something, I'll take notes either about the lyrics or about the song. I'd like to be able to link from Org Mode directly to either that song, that album, or that particular timecode. I don't have that yet, but I'm working on it. I think I'll probably lean on it quite a bit once I have it.

Sacha: Yeah, yeah. I saw your tweet from May, I think, where you're talking about coming up with this way of taking notes. think if you come up with maybe a custom Org Mode link type that can store the annotation and then let you go to it, I think that would be really interesting. Especially if you figure out, okay, like, are you taking notes in the album? Are you taking notes on the song? Are you taking notes on this moment in the song? That could all be very cool.

Ben: Actually, do you mind if I share my screen?

Sacha: Please.

Ben: So one of the things I wanted to kind of note was... Let me... Oh yeah, this is actually going to be further embarrassing. I'm a terminal Emacs user.

Sacha: I saw. Can you increase the font size, though?

Ben: Absolutely, yeah.

Sacha: Resizing your terminal so it's smaller makes everything look bigger...

Ben: Is that better?

Sacha: More. Some of us are older. Thank you.

Ben: One of the things that's kind of unusual about my MPD configuration is I've got a satellite config. Sorry, the line wrap is a little bit off here. What this means is that I have... the household file server maintains the MPD library, but I've got multiple playback nodes around the house. What that lets me do is...

Sacha: You can play stuff on this...

Ben: So what this means is that I'm controlling the... well, in this case, that's a little MeLE Quieter3C that I've got in the living room that's kind of like the the home media server, the home playback machine. Fundamentally, I'm an ops guy, I'm a sys admin, and I've got, unfortunately, a fleet of machines around the house. What this lets me do is easily control each one of them. Instead of each one maintaining its own library of music files, the file server itself indexes them, which means that library updates are almost instantaneous, instead of having to read over the network to pull metadata out of each individual file. So having a satellite setup lets me... The real benefit is that MPD tracks albums, directories, and files as URLs. That means that I have a single global namespace of URLs for all of the media that's currently in the library, which means that I can annotate from any machine, but have it mean one thing. It makes it convenient for navigation, but it also makes it convenient for keeping notes, which I'm currently doing manually and working on those Org link types to be able to make it a little bit more smooth than it currently is.

Sacha: So you've got your central store of music files. You've got URLs for them so you can talk about them. That's just one identifier per song. You've got multiple speakers that you can use your completing interface to say, okay, I want to play this over there. You have Emacs controlling all of that.

9:13 Emacs on Android with Termux

Sacha: Now, is that Emacs on your laptop and you just take it around and you say, okay, I'm going to sit in the living room for a little bit or whatever and play there. Or do you... Ah, there you go. That's what I was going to ask. All right. So Emacs on your phone. The Android port or Termux?

Ben: I have both installed. I think you actually saw this a few months ago when I was running performance comparisons between the Termux version of Emacs and the native port, and found that the native port generally ran anything CPU-intensive roughly twice as fast. But I still use the Termux version because it's... I'm not sure if you played around with the Android terminal virtualization layer at all, but it's not great. I really appreciate the integration that Termux gives me with Android features. For example, being able to query the sensors, such as GPS or temperature sensors, and I can actually pull those in from the Emacs side. And that's something I kind of want to get into.

Sacha: What do you think of using the temperature sensors for? What can Emacs do with that?

Ben: It's not so much the fact that I use the temperature sensors as that when I pull the sensors, that's the most remarkable value that I get out of it. But one of the interesting things is the barometric pressure sensor, which gives me height, which matters because when I'm out and about and if I stop to record an entry in my journal, for example, I'll just pull the sensors and dump them into the header in the entry that I'm writing. The barometric sensor, I'll get the GPS, so that'll tell me what the actual height is at that location on the earth. The barometric sensor also gives me a little bit of insight into the weather. So it's not so much the temperature sensor is what my temperature is, but just like if it's a hot day or not.

Sacha: I am very curious about that setup. So if you happen to share your, I don't know, Org capture for Termux that includes all these things... You don't have to show me the actual stuff, but you know, at some point I think other people will be curious about what kind of benefits they can get from running Emacs on their phones.

Ben: So, I mean, I guess I'll... One of the benefits that I get is the ability to keep shopping. So I'm a little bit of a militant cyclist. One of the things that I often do is leave

image from video 00:12:04.333Ben: notes about things that I need to take care of in particular areas of the city. The nice thing is that I can just drop them directly in commits right as I'm going. So I often have a long list of updates that are from Emacs on my phone, just because it's convenient. All right. There we go for Monsterdon, in fact.

Sacha: Nice, nice. Then that's Syncthing or whatever else to just get it copied back to your laptop or just on your phone?

Ben: Straight Magit mode.

Sacha: Oh, yeah?

Ben: That's one of the things that I found was a little bit clunkier when I was running virtualized Emacs under the Android emulator and also the native Android port of Emacs. They are a little bit more troublesome to get Magit to work. Because I rely on that for syncing back and forth from my phone, that's one of the reasons why I stuck with Termux.

Sacha: Very cool, very cool. I like Termux's little bar of extra keyboard keys that you can have, so you can have a regular keyboard and then you can just have your Controls and your Alts and whatever on that little extra bar. Termux is quite interesting.

Ben: I think I'm probably pushing it harder than it is meant to be pushed.

Sacha: That's the fun of it. I don't exactly know how everything will shake out, but probably with Google trying to lock down the developer ecosystem in a few months, right? They're saying, oh, you know, it's got to be ADB in order to get these unsigned apps on. We'll have to see how it all shakes out. But I'm hoping Termux can survive because I like that one too.

Ben: Yeah, me too.

Sacha: Okay, so you've got interesting music, an interesting music setup with lyrics and playback and all that stuff. You've got your phone, which also runs Emacs and from which you can, you've also set it up so you can control your music from your phone?

Ben: Yes.

Sacha: Okay.

13:44 Keyboards and other devices

Sacha: When I was reading through your toots, I noticed you like to play around with other keyboards and other devices like the 8BitDo. Do you have any of that talking to Emacs too?

Ben: [Keychron B11 Pro is] the keyboard I'm currently using. I got this so I could keep it in my purse and just like walk around with it, but it turns out it's super comfortable and I'm accidentally using it as a daily driver.

Sacha: All right. Name-drop the keyboard for all the people who like the device recommendations.

Ben: It's a Keychron B11 Pro. It runs ZMK. ZMK, I suppose. And if you've seen me interacting with Pete Johanson on Mastodon, he's the lead developer of that firmware package. It's a little bit like QMK, except that fundamentally QMK is a polling architecture, and it works really well for very restricted microcontrollers. ZMK is interrupt-based, which means it is tremendously more efficient in terms of power draw. So if you want a Bluetooth keyboard, you should probably run ZMK on it. Anyhow, yeah, it's fantastic. And I do have a bit of a keyboard problem where I tend to...

Sacha: Many Emacs people have keyboard problems.

Ben: Right? I feel like I'm in good company right now.

Sacha: Yeah, yeah, yeah. So, devices, yep, gotcha. And this has become your main keyboard even for regular computing?

Ben: In the last couple of weeks, yeah. It's super comfortable. Because it's so flat, I can get away without having to use palm rests to actually keep in a decent posture, because of the curvature of it.. Like, it's an Alice layout. The key travel isn't too bad. It's actually quite comfortable. I found that I needed a little bit of acclimatization to get used to split keyboards. This one has roughly the spread of a split, but it seems to be easier for my muscle memory. So yeah, I didn't intend to leave it on my desk, but it stuck and has kind of stayed there for now.

Sacha: Does it have any special ergonomics for all the modifiers that we like to do? Or do you just use Caps as Control or whatever else?

Ben: Actually, I don't use Caps as Control and I actually really need to get into remapping that. ZMK has a very rich remapping story, as I expect you to imagine, from a custom firmware. The macros are intense, and you can get really deep in customization. I have done none of that on this keyboard yet, because it's only, I think, a couple of months old at this point.

Sacha: You've been settling in. As you said, this has been your main keyboard for a little while. Charlie Baker says, "yeah, I love the split keyboard. Recently bought one myself. I was getting so much neck pain, you know, shoulder and neck pain from so many hours keeping hands close together." But the split lets his shoulders relax. So probably you're getting the same, like, ha, my arms.

16:44 Benefits of a split keyboard

Ben: The two things that I first noticed when I moved to a split keyboard was one, my wrists started feeling a lot nicer and two, I was immediately able to bench press like 20 pounds more the next week. It was amazing how much of a difference it made and it showed up in the data.

Sacha: Wow. There was a weightlifting talk at EmacsConf last year, I think. So there's a surprising overlap between the people who are checking their weightlifting stats and the people who are into Emacs. Naturally, with Org Mode. There you go.

Ben: Let's not look at those numbers too closely. I'm not too proud of a bunch of them. But yes, I find that Org capture templates let me keep on top of that and not really think about it, which is great because you don't want to think about it. You want to gather the data and think about it separately so that you can stay emotionally divested from what the numbers mean.

Sacha: I know. I'm totally happy to dig into the Org capture, especially if you do any graphing. People always love graphing their progress, right? But if you're like, I don't really want to show my numbers at the moment, that is also understandable and okay.

Ben: I don't, I'm afraid. Sorry.

Sacha: That's okay.

Ben: It took me a couple years to get used to being on camera at all. I don't really like my appearance very much. I'm working on that, as you can see. I've had to work on that to be able to work remotely. It's a work in progress. I'm getting through it.

Sacha: You know us. We're very much focused on text. In fact, you even use Emacs in the terminal. That's very text-y.

18:22 Meeting workflow

Sacha: One of the interesting things actually that I wanted to ask you about since you mentioned meetings is you probably also have the role of designated note-taker. You mentioned in one of your toots that you take notes and people are like, what are you doing that in? How are you taking your notes? And it's Emacs.

Ben: Yes, so actually that's one of the things I should lead off with as an apology. I probably won't be able to share many of my capture templates because I don't use them in my personal life very much. They're mostly on my work machine. I've got capture templates for impromptu meetings where it's just like an exploratory, we have a problem we need to solve, we're kind of talking through a discussion, a separate capture template for meetings with agendas to make sure that we stay on them and that we log decisions, and a separate set of templates for... So I have a team of direct reports and they each have different cares and different topics that we're working to develop in their professional careers. I find that it's really useful to be able to keep some continuity between our conversations. It also makes it very easy to export that entire dataset, share it with them to make sure that they can consult it at the same time. If I got anything wrong, I can fold their corrections in. But all of those templates, unfortunately, are on my work machine.

Sacha: We'll just sketch out the general idea in abstract details and then people who want to implement it for themselves can fill in the blanks. For example, when you're having a meeting with your direct reports, are the tasks related to them in an Org agenda? Are you using dynamic blocks? Is it tracked somewhere else or is it in Org?

Ben: It's straight in Org mode. So most of the touch points that we have are more about professional development and their cares and concerns, rather than specific deliverables. Usually deliverables we manage at a team level. But if there are specific things that individuals are working on, they will be in to-dos under their subheadings in a way that show up on the agenda if we have assigned deadlines for them. But generally, if there's a deadline on a task, it's because I'm doing something and they need to track it, or they're doing something and I need to track it. If I'm the only guy using Emacs, then Org Mode won't work for that, so there aren't a lot of those. But if it's just something that I need to check up on to make sure that something that... Like they've got planned leave for example, or they have a cousin's wedding that they need to go off to, or something that I just need to keep in my brain that's not necessarily deliverable, then it would be appropriate to keep that in a place where it'll only show up on my agenda. So that's the kind of decision making that I apply there.

21:11 Narrowing

Sacha: And you mentioned you have a subheading, I guess a subheading per person or sort of... Or do you use tags to keep track of something that might touch several people?

Ben: Usually a section per person, and that's more of a convenience than anything else. That lets me narrow to just that subheading and share my screen during the meetings. Then I don't have to worry about accidentally leaking anybody else's information into the screen share or anything like that. Obviously we let off with conversations about them being all right with that. But the ability to very clearly and simply delineate "This domain of my notes pertains to this person" and being able to be confident and share that confidence that there will be no leakage means that we can explore topics and talk about them in a way that might otherwise be a little bit more restrictive. So being able to do that simply, and being able to establish a very clear delineation around whose information belongs where and where it should be shared turns out to be pretty valuable.

Sacha: Yeah, and that's a technique I think that especially people who are new to Emacs and who aren't used to narrowing and widening might not know how to use effectively. I think narrow is even one of the commands that's disabled by default. You've got to say, yeah, you know, I'm not scared. I know what to do.

Ben: Yeah, it's kind of bizarre to me that it is, but yeah.

Sacha: I can imagine people accidentally triggering it and they're like, oh no, the rest of my file is missing. But if you know how to narrow to a region, and Org even has those commands to easily narrow to a subtree... I think it's even part of the default speed command so you can trigger it right from a heading. But it's great for that kind of restriction.

22:58 There's even an internal Slack channel about Emacs at Ben's company

Sacha: Okay, so the reason why I was asking about that is because some people are working with people who are not using Emacs, so it's very interesting to see what the kinds of... It's very rare for people to work with other people who actually use... Are there any other Emacs people in your company, for example?

Ben: There's an entire Emacs Slack topic about that, yeah. It's kind of great.

Sacha: What is that like to have co-workers who do Emacs? Because this is a rare experience.

Ben: It's super cool. It's also neat to see the very, very different ways that people use it. But yeah, oftentimes people will talk about problems that they have with particular internal tools, and somebody's like, oh yeah, go check out this repo on GitLab that I published last week where I got sick of it and decided to solve that problem categorically. It's actually super cool. And some of the folks at... Generally, I tried not to mention my current employer at any point. Obviously, it's not secret. It's in the init file. But yeah, I don't tend to get into that deeply. But some of the other people who work at my company, they maintain venerable Emacs packages. So it's awesome to be able to go and talk with some of the folks who I've been working on the code that I've been using for a decade and we are now coworkers. It's lovely.

Sacha: Oh, that's so nice. I'm glad you have that kind of little community in there.

Ben: Yeah. Bunch of nerds.

Sacha: So I suspect some people will be looking up your company after this. I think it's also mentioned in LinkedIn and sort of like, okay, let's see if there's any job openings.

Ben: If it's mentioned on LinkedIn, that is somebody else. I haven't logged into LinkedIn in 15 years and I never will.

24:50 Ben keeps Org capture templates as individual files and adapts them to different meeting flows

Sacha: We do have a question from Shae. Shae is asking, how do you make a capture template to stay on agenda and record decisions? You got any tips for that? I'm guessing this is more of a human thing rather than an Org thing, but maybe you have some ideas on how you keep something on track.

Ben: So I'll actually push back on the "It's a human thing rather than an Org thing". I strongly believe that one of the real values of Org Mode is that it's a very plastic system. Fundamentally, I think that it is a human system because it allows you to express exactly those kinds of trade-offs in a really, really fluid way. I love the personal information management that Palm Pilots provided, for example, but it was pretty restrictive. One of the things that I love about Org Mode is that if you find that a particular person has a particular conversation style, it's really easy to modify your Org Mode capture templates to be able to capture that particular flow that you have with that person. Or with a particular group of a recurring meeting, for example, that tends to flow in a particular way. Super easy to update the templates that I use to capture those particular meetings to make it easier to match the general conversation flow with the notes that I will be taking about it.

Sacha: Wow, that sounds pretty sophisticated.

Ben: Well, I mean, that's the thing. It's not sophisticated. It tracks the human process very easily. So it's really lightweight. So you don't have to have a lot of sophistication to make it very, very useful. You just have to have a feedback loop that you can tune every time with one or two minutes of effort. And that's one of the reasons why I depend on Magit mode so much is that it lets me track those things. But yeah, to answer Shae's question about how do I track those particular things. So if it's a meeting where one of my direct reports has a particular set of topics that we tend to investigate, like somebody who's concentrated on career growth. So we're talking about the areas in which we want to see development. I'll absolutely update the capture templates for that particular person to say, all right, here's what we talked about last time. Here are the things that were done between our last two conversations about how we move in that direction. Were they successful or not? Did it require a lot of effort? So was it something that more effort should be put into to be able to drive down the work over time, to be able to produce those results? But yeah, that goes into the templates and that goes into the cadence of conversations that we talked about in Capture.

Sacha: So that's really interesting. You modify the capture templates with the notes that you want to have easily available the next time you chat with them.

Ben: Exactly, yeah.

Sacha: The capture templates are still defined as a setq somewhere in your thing, or are you going into the customized interface?

Ben: So I actually keep the capture mode templates as raw files that are referred to, and that makes it easier to version them in a way that like, I mean, sure, like my Emacs init file, if you look at the Git history of it, it has a whole bunch of different...

Sacha: I had not considered having capture templates as files files. It worked out really well.

Ben: So you can see that... It's a little bit hard to see with the font this small, but you can see that I've got a lot of changes to, for example, my init file, but keeping them in individual capture mode template files makes it a little bit easier to just look at the history of that particular file and see why particular changes were made.

Sacha: I'm going to try that. I think that's a great idea because it allows you to be a lot more granular about the notes.

28:45 Personal-scale software and the journey

image from video 00:28:28.300Sacha: I saw in that very brief flash of your change log message that you like to write fairly detailed commit messages that talk about why a change was made instead of just "a new function, new command," very terse updates that I sometimes just try to get away with. Tell us more about that, because I think you've had a couple of toots about reading source code and reading commits.

Ben: Yeah. So I guess one of the things that I most appreciate about software in general, and specifically personal software, like personal-scale software that's been written by an amount of people that you could fit into a room to have a conversation about it... One of the things that I most appreciate about that is that almost all software written that way is fundamentally a diary about the way that a person learned how to solve a set of problems that they might not have known about when they decided to at the beginning. It's this fascinating process of tracking somebody's voyage through the problem landscape as they discover other people who have touched on topics that are tangential to the problem being solved by that software package. It's such a personal and fascinating experience to see somebody go from "I know just enough about a problem to be able to decide that I want to build a machine that works on it" to "I have this deeper understanding of how the problem actually exists in the broader set of things that people care about, oriented along the axis of what machinery can do to help solve parts of that problem." The commit logs for a program are like a map through that territory. It's wonderful to read. It gives you a lot of insight into the person doing the navigation. When you see 16 commits on December 24th of 2023, like, that person probably had a little bit of time to work on it. Then, when you see a bunch of commits that are 5 p.m. Monday to Friday, like, okay, this is probably done in a particular way. It's this deeply personal process of seeing how problems are learned about. I just really appreciate that.

Sacha: I think what you're saying about personal-scale software and getting a sense of people's journey as they learn to understand a problem and as they start to prototype a solution... Because you never quite come across the right solution the first time around. You're figuring things out, You're borrowing things from other people. I think that will resonate a lot with lots of people in the Emacs community, because Emacs use is so personal, as you mentioned when you were looking at the Slack channel. I was wondering, in your personal practice, as you figure things out, what kinds of things help you? Is it mostly a matter of actually sitting down and taking the time to write the literate programming stuff around the code blocks or the commit messages, or are there other tools or techniques that help you do that? Are there tools or techniques that help me write down your journey along the way as you think about the code? What's your practice? For example, when you come across something that you want to figure out, how do you go about doing it?

Ben: So it depends on how I'm approaching the project. One of the neat things about software is that it's a document and a device at the same time. You can care about it because of the thing that it does, or you can care about it because of the information that it captures. If I'm digging into a program because it does a thing that I want to learn, then I'll pay attention to the device aspect of it. That usually means that I'll start with its own documentation. If it has a man page, I'll read that. If it has user docs, I'll read those. Usually, I'll start keeping notes in an Org Mode file, because it's easy to hyperlink back to it and add my own annotations in parallel to the actual authoritative source. If I'm reading software primarily as a document, then I'll start by reading the source code and the commit logs, usually the most recent ones, and then I'll jump back to the beginning of the project and read upwards at the beginning, and then fill in the blanks iteratively, if it's a project that's small enough or has little enough history that I can do that. Again, I'll usually start an Org Mode file specific to that particular exploration that will let me organize my notes as I go. I really do rely on the external brain that I can keep in an Org Mode file. I tend to have a pretty decent long-term memory, but being able to bridge the gap between short-term memory and long-term memory is super, super useful. Leaving myself hints that let me dredge things back out of long-term and reload it into the hot cache of short-term really, really helps out, because that lets me maintain that flow state or get back into that flow state. When you've got like the whole program, all the context that you've absorbed up until now and the ideas of the areas that you want to investigate, being able to hot-reload all of that and then pick up where I left off is super useful. But the meat brain can't do it. I need the machine brain too.

34:07 vc-git-grep for finding notes again

Sacha: Tell me about this dredging up process. Are you a lots of little files person? A couple of large files? A project file, there's an Org file in each project that you look up? How do you find things, especially if you don't remember the exact words?

Ben: So it's usually like an Org Mode per category, and they get consolidated. Let me shrink this down a little bit. So usually it's an Org Mode category per file. If there's something super specific, then usually it'll live out in its own place until I get around to...

Sacha: I love that you have an Org File specifically for Mug Cake.

Ben: But that's the thing. It'll live off in its own thing until it gets integrated into the list where the long-term stuff lives. I promise this is pertinent to your actual question.

Sacha: No, no, this is very pertinent.

Ben: Usually, lots of little files while I'm still working on something, and then as that something becomes part of my larger life and has links to other things,

Ben: then it'll kind of get centralized into one of the Org Mode files that has a broader topic purpose basically.

Sacha: If it's very long-term and you can't remember the exact words to find something, how do you generally find find your notes?

Ben: That way.

Sacha: You start grepping various keywords and try to find it.

Ben: Yeah. So one of the things that I don't yet have turned on, and actually you inspired me to look into this, was so... Actually, do we have enough time? Yeah, okay. I'm just looking at the clock. One of the things that I wanted to get into was long-term searching and searchability. Yeah. So I use SQLite's indexing for a lot of things, and I really appreciate its porter stemming because it lets you search for stemmed words, which are kind of approximate matches, which is useful, but less useful than vector databases. You actually put a little bit of work into indexing topics based on vector similarity.

Sacha: Which I haven't gotten back to, so I'm glad to see you managed to experiment with it, see what you come up with.

Ben: I don't have anything to show yet, except that it's an interesting topic. Because I'm word-oriented, I will often remember individual keywords, or I'll have enough patience that I can sift through a list of potential keywords as I'm grepping for stuff.

36:55 Add keywords to make things easier to find again

Ben: If I find that my first three or four attempts at searching for a keyword don't find the topic that I'm looking for, once I do eventually dig up the topic, I will add those keywords that I was searching for just so I can find it next time, expecting that future me will probably behave more or less like current me. But yeah, being able to use a vector database to search for headings that include related topics instead of related words... I'd really like to get there. I'm not there yet, and I think that's going to be interesting and useful. I also think it's going to be challenging to represent Org Mode's hierarchical structure to restrict the training of particular vector sets to be able to cast an increasingly wide net for where I want the searches to run. I don't know how that's going to be solved yet, but I'm going to be looking into it.

37:47 Keybindings and terminals; wezterm

Sacha: @PuercoPop has a question regarding terminal Emacs. "Do you need to change any of the keybindings to avoid clashes with the terminal?" Some keybindings don't work on terminals, or some terminals already have these keybindings set.

Ben: So I have good news and bad news there. The good news is that... One of the terminals that I'm using right now on most of my systems is Wezterm. It's really good. I started off with [meant to say Kitty], and I kind of bounced off that project because of some of the behavior of the lead developers. I won't get too deep into it, but what I found is that Wezterm... It gives me very little friction that way. It doesn't have a lot of its own keybindings, and that's a relief. It means that I really don't have to... I don't think I've had to put any time into customizing Wezterm to get out of the way of Emacs or Screen. I should mention, I am running Emacs within Screen, so that introduces another layer. C-a a, for example, is beginning-of-line for me, even though C-a itself is the default Emacs keybinding. But yeah, I think that I ended up choosing terminal software specifically on that merit, so that it doesn't get in the way. That's actually one of the things that Termux is... The default Google keyboard keeps stealing key bindings. It'll update, and all of a sudden, I can't use a particular Alt key combination anymore, because now it invokes a Google keyboard shortcut for pulling things out of the Android clipboard, for example, which is really kind of annoying. But yeah, in terms of terminals on full-fledged machines, I generally don't have that particular problem. Except for... What was the name of it? It was... It was a zap-to on-the-screen package that alphapapa wrote, I believe, that I... Actually, let me just look it up. Yeah, Avy.

Sacha: Oh yeah?

Ben: So I wanted to start picking this up in 2021, and yeah, control colon doesn't work in terminals. So the mode itself is fantastic, and when I'm using it in a GUI Emacs, it's very useful, and I rarely use it now specifically because of that particular terminal problem. That is self-inflicted. That is not a problem with the package. That is a me problem. But yeah, I think this is the notable one that I bounced off of.

Sacha: Yeah, just trying to find the right, you know, a key binding that will pass. Because you can't get used to key binding in one system and then not have it available in other systems. It's just going to mess with your brain. So yeah, Ray points out, yeah, Google steals Control Shift K, which he uses to kill tabs to the right. So it's like, oh.

Ben: Infuriating.

Sacha: Yeah, yeah. And of course, none of the standard keyboards have a super key on the thing, so you can't just tack on another modifier that'll get through.

Ben: That's actually one of the reasons that I picked up this particular keyboard is Brian Carlson. Another Torontonian. He works on Git LFS and some other stuff. He was specifically looking for a keyboard that had a super key that he could remap. So four keys to the right of space, which this one has. And because it's ZMK, it's remappable. I think this might be suitable for his purpose, except that he wants a QMK keyboard, specifically because the development tools for QMK are packaged in W, and that's a plus for him. Anyhow, yes, I agree. Like, not having a super and a hyper key on a keyboard

Sacha: feels like like one of your fingers that are cramped up we need more modifiers well I mean you know pipe organ Tell us about that.

Ben: What is this? Oh yeah, foot pedals. Yeah, and I actually do have these wired into a little Atmel microcontroller running QMK. I honestly tried the foot pedal thing for a little while. It was hilarious. I did not find it useful.

Sacha: I don't have the hand-eye-foot coordination to do that thing at the same time.

Ben: Maybe if I had learned piano as a kid, it would have been good. But yeah, I don't seem to be able to do it. But I gave it the old college try and it was fun.

42:38 Timers: tea-timer, tmr

Sacha: Okay, I had a couple of things I wanted to ask about in your config. You have two types of timers. You have tea-timer and you have Prot's TMR. Do you use them for different purposes? What's going on here?

Ben: So I'm trying them out. I tried TTimer first because it was the first one that I found, and it was useful. I was actually using it in meetings because I would, when I was trying to keep us on topic, I would use that to remind us that, oh, we've got four other topics we need to get through. We're trying to give this one five minutes. We're running up on four. And it was just because it was super low overhead. It was easy to pick up. It was easy to have it displayed on my screen. And it didn't feel like I was... Running a chess timer on everyone. It's very subtle in the mode line. It was useful. But what I found was that when I was... Running multiple timers simultaneously. TMR, just the fact that you can list all the timers and manage them in a separate buffer. It's richer and I appreciated some of its documentation more. I haven't fully switched over to it yet. I'm still in exploratory mode. In fact, this is probably like... So I actually have a bunch more packages installed than I'm currently using. So I'm going to shrink this down a little bit just so that it doesn't line wrap.

43:57 Different stages of package use

Ben: But yeah, so I've got, I think about 140 packages locally cloned. I've got, as you can see in my init, about half of that actually installed. There are various phases. I've got a clone, but I don't have it in my init. Or I have it in my init, but there's another package that offers similar functionality. Or I'm all-in on this particular choice and I'm removing the other ones. It's a gradual kind of progression.

Sacha: Yeah, we're all auditioning packages to see if they fit in our workflow and all that stuff. I was curious also about your elfeed things. You have a few things related to elfeed. Actually, do you want to talk about the thing you just highlighted first?

Ben: No, we'll get back to it in a sec. I'm keeping an eye on the clock.

Sacha: But yeah, elfeed.

44:47 Elfeed

Sacha: Yeah, you've got a couple of interesting things in your elfeed setup, including picking a search from a bookmark or other shortcuts like that.

Ben: So I have discovered in my conversations with the new maintainers for elfeed that my elfeed habits are very deviant. So let me actually start off by going through... You can see that like the top of my elfeed list is kind of in one format and down at the bottom, the ones that are closer to present day are organized in a different way.

Sacha: You've got tags now.

Ben: So my feed list is, I mean, it started in Google Reader. It's kind of been forward ported since then. It's long.

Sacha: I love the comments.

Ben: But one of the consequences of having a long feed list is that I have an enormous elfeed database. And I use it for completely different purposes. So for example, I'm going to show off that little default search. I keep an eye on projects that have releases that aren't packaged by Debian, for example. So I've got this little ATS Mini. basically a small AM FM radio that happens to run on ESP32 and the firmware for this community developed and it's kind of interesting but like that's not packaged by Debian so I pay attention to or I subscribe to the release feed for that particular project. I do keep in keep an eye on the Linux kernel especially these days because The gallop of security vulnerabilities coming out of mythos analyses right now means that I have to pay more attention than usual to fresh updates. So generally I run Debian stable, but I do run kernels from backports and I want to know when those are available. MeshTastic. I was paying more attention to this a couple of weeks ago. I'm not going to reach that right now. But yeah, the local MeshTastic community in Toronto is plagued by a couple of griefers that make it a lot less fun. So I'm paying a bit less attention to that right now. But yeah, so like one of the bookmarks that I have is software currency. Another one is, for example, the YouTube channels that I subscribe to. Thank goodness for Elf YouTube. It is so nice to be able to get the transcripts for things directly in there.

Sacha: There's even a sponsor block integration so you can skip all the promotions and stuff.

Ben: Yeah, I mean, so again, my use of YouTube is also deviant in that I pretty much strictly subscribe to RSS feeds and they're downloaded onto the file server. So when a new recording comes out, it gets dropped there. I'll watch it. And then I've got a little widget that scans through my Kodi database for watched files. Once YouTube files show up in the watch list, they're automatically purged. And it means I just never see an ad. It's not just satisfying. I don't think that I would be able to pay attention if I was being constantly interrupted because of the way that my brain works. But yeah, so being able to quickly search for YouTube is one thing.

48:36 Spoilers

image from video 00:48:40.433Ben: I do have articles that I've marked as spoilers for media that I haven't watched or read yet. Maybe I go to an extreme degree, but I'll try to avoid previews for new movies, for example. I do want to actually go back to them later on. Marking articles as having spoilers that I want to revisit later on is an easy way of not having to worry about it anymore. For a while, back in the days when I was paying more attention to... Enter the Dragon was the sequel to... What was that TV show? George R.R. Martin... Seven seasons and it went badly off the rails in season six.

Sacha: Game of Thrones.

Ben: Thank you. So when I was watching that for a while, several of the sites that I was reading would have individual episode updates. I really appreciated having a list of Elfeed keywords that I could automatically apply those tags to. I wouldn't even see the headlines because it was problematic enough. I've become less...

Sacha: Nice.

Ben: I've been putting less effort into maintaining that now, but the infrastructure is still there, and I can lean on it if I need to.

49:53 Comparing different news sources

Ben: One of the things that I don't have set up right now is a quick search for the municipal topics that I cover. I tend to subscribe to a lot of news because I found that, for example, it's interesting to see how the Toronto Star covers stuff differently from other local newspapers. It's useful to be able to quickly pull up the five or six publications that cover news in the same way and then look through the annotations for them or add the annotations myself. I can see that this particular story was covered by this journalist in this publication in this way, and then it lets me cross-reference so that I can pay attention to topics that are under-covered or publications that habitually leave out particular aspects of news stories. It lets me pay more attention to the trends of publications as well as to the stories that they're covering. The consequence of that is that my Elfeed database is 4.5 gigs. It's common for me... I don't know if that actually shows. It's common for me to have like 65,000 articles in like the six month horizon for the default Elfeed searches. That means that searches and redraws are expensive, even on a relatively performant machine. You've probably seen some of the workarounds that I've got. This little bookmark selector is one of those workarounds. Elfeed's interactive search: super, super useful. But if you're trying to do it like this... Actually, it's not so bad.

Sacha: I love this. When you see someone using Elfeed for 65,000 items, you get a sense of what it can be used for when you're really stressing it.

Ben: And the organization of the bookmarks that I have means that I do have one river of news of all of the things that I want to pay attention to. But it's seven or eight pretty divergent topics with not a lot of overlap. It's neat to be able to think of Elfeed as the thing where news information comes in. The individual bookmarks are the topics that are grouped together that I actually care about and want to read about in concert with each other. If I specifically narrow it down to just Emacs stuff, one of the things that I can easily do is add a bookmark for that search. If I name it... Now that I've got that bookmark saved...

Sacha: And then it's like, bookmark annotation.

Ben: Right. It ends up in my dot file as a git commit.

53:13 Bookmark naming conventions

Ben: Now that that bookmark exists, simply because of the naming (elfeed-search-...), now it shows up in completion.

Sacha: Precisely this sort of stuff. I am under-utilizing bookmarks, I think.

53:24 Naming conventions simplify building new workflows

Sacha: I love this idea of using bookmarks with a naming convention and then writing Emacs Lisp to take advantage of that naming convention to make that easy to jump to, easy to use in other things.

Ben: Yeah, it means I don't really have... When I notice that there's a thing I don't have, it diminishes the activation energy for building a new workflow. It means that I don't have to put a lot of thought into it. I can quickly do it. If it turns out to not be useful, I can quickly get rid of it.

Sacha: Very cool.

53:50 elfeed-curate for annotations

image from video 00:54:52.533Sacha: I had one more thing that I wanted to ask you about elfeed that I want to squeeze in, in the five minutes that I have before the kiddo comes out for lunch break. This elfeed-curate that you're using, this is the first time I've come across it in the config. Are you sharing your notes or your selections with other people, or just for yourself?

Ben: No. It's just for myself. What I'm trying to replicate is, back in Google Reader days, I really appreciated how when you added an annotation to an article that you were reading, by default, that annotation would be viewable by other people in your social graph. That was super interesting. Sometimes you could also add personal-only annotations. Actually, I don't think that's the keyword that it uses. I think it’s just +ann.

Sacha: Also, because you have an Emacs keyword on it, so I don't know whether you have any annotated Emacs ones.

Ben: Yeah. Well, I mean, generally, if I've added an annotation, it will be. So, for example, here. Right? Super useful. Well, super useful for me, anyhow. If I find that there's an annotation that is more... This is inflammatory. It doesn't need to go out on the web.

Sacha: Sorry, did you need me to kill the stream? I have a 10-second window.

Ben: No, it's all good. I'm not worried about sharing this, but it's not something I've posted. What the nice thing is, is that if it is something that I want to share, it's really, really easy to just drop this into Mastodon mode.

Sacha: Very cool.

Ben: That's one of the ways that I use it. Because the annotations are just Org Mode files, you can add links to other things and it becomes just as useful as anything else.

55:46 mytoots archives Mastodon toots

Sacha: You're saying this can flow into Mastodon and from there, once you toot it... I think you're using mytoots that you mentioned in your config for archiving it? Or searching, yeah, okay. Oh, except it's currently not working.

Ben: Yeah, I don't have it loaded right now. So mytoots, it just loads the backup of your export archive. So it loads the... What's the most recent one? So yeah, it was your outbox JSON file, which is the most recent one here. I've got an Org Mode reminder to download it roughly quarterly. My outbox is about 100 megs right now. Compared to 4.5 gigs for elfeed, it's not so big. That's not going to redraw properly. I was just going to show it. My resident Emacs memory size right now is about like five or six gigs. It's a little bit embarrassing. By comparison, 100 megs of JSON in RAM is not so bad, but having an instant search for everything that you posted and being able to bounce back from your local archive to the conversation thread that's live and see anything new that comes in... Again, it lets me exercise that outboard brain kind of idea. So yeah, mytoots is super useful.

Sacha: I like it a lot.

57:06 Mentoring offer

Sacha: The last thing that I want to ask before the kiddo (because I have two minutes) is that you have a mentoring offer pinned in your Mastodon, too. Have people taken you up on it, especially if they've taken you up on Emacs? Is that ongoing or forgotten about or whatever?

Ben: Not forgotten about. Very much real. Still open. I haven't refreshed that offer recently, but it's still pinned for a reason. I think maybe a dozen or so folks have asked for that. 9 or 10 success stories, I think. Nobody's asked for Emacs tutorialship yet. That's fine. Again, I love Emacs. I use it. I don't often recommend it. But if anybody was curious about that, I would be very open to the idea.

Sacha: All right, so if people want to also develop a very interesting elfeed setup, they know who to talk to.

Ben: Please, I would love that conversation.

Sacha: Thank you so much. Yes, go ahead.

58:02 A local instance of public-inbox can let you use Gnus to read mailing lists quickly

Ben: Oh yeah, there's just one last thing I want to mention, and I realize we're right up against time. I use Gnus. I use mu4e for email, but I use Gnus for reading mailing lists. I just wanted to strongly recommend to anybody who is thinking about it... This is amazing. You gotta do this. public-inbox lets you keep a complete local archive of the entire mailing list. Searches are instant. Tracking threads is instant. Check it out. It's fantastic.

Sacha: That's great because Emacs-devel has a gazillion threads. How do you even keep track of all this stuff? But if you've got Gnus and if you've got this set up, then you're no longer dependent on the good graces of Gmane being around as an NNTP to mailing list gateway. @JonKishore11 wants to know if you have a YouTube channel. I'm guessing you don't yet.

Ben: I don't really like my face very much.

Sacha: Ping Ben on Mastodon and ask about this mentoring thing and then share your notes so we can all learn from it. Thank you so much for today. I look forward to chatting with you more through toots. What is the verb, you know, in the fediverse? All right. Thank you so much.

Sacha:

Chat

  • sachactube: ​​only slightly panicking behind the scenes 🙂 Nudged Ben by Mastodon in case we got our wires crossed
  • sachactube: ​​yay, he's here, just getting sound sorted
  • symbiopoyesis: Good morning
  • x_goose_x: ​​hey gnomonnnnnn
  • CharlieBaker707: ​yay! love the split keyboard. recently bought one myself. i was getting shoulder and neck pain from so many hours keeping by hands close together, but the split let's my shoulder's relax.
  • ShaeErisson: ​How do you make a capture template to stay on-agenda and record decisions? Any tips?
  • PuercoPop: ​​Regarding terminal emacs, did they need to adapt any keybindings to avoid clashses with the terminal keybindings?
  • AyanRaza-n1x: ​​is that the creator of emacs?
  • Ray-On-Emacs: ​Yes! Google steals C-S-k, which I use to kill tabs to the right on Vivaldi!
  • CharlieBaker707: ​elfeed is like a distraction alleviation machine. I agree with Ben, I don't think I could consume any of this information outside of Emacs. Ads and even varying formats distract me too much.
  • JonKishore11: ​​do he have YT
  • sachactube: ​​Thanks for hanging out, everyone! =)
  • gnomon027: Thanks so much for running this whole series, @sachactube !!
View Org source for this post

You can e-mail me at sacha@sachachua.com.

-1:-- Emacs Chat 25: Ben Zanin (@gnomon@mastodon.social) (Post Sacha Chua)--L0--C0--2026-06-04T12:50:07.000Z

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!