Charlie Holland: Emacs Teaches Emacs: The Missing README

1. Two Keys   emacs help

june-fish-banner-2.avif

Learning Emacs is not about scouring through documents and memorizing facts.

Those who use Emacs fluently know that the real skill is knowing how to ask Emacs about Emacs. The answer to any question you might have about Emacs lives behind just two keys: M-x and C-h. If you internalize those, plus a handful of command prefixes for the auto-discovery commands, Emacs will teach you whatever you need to know, on demand.

2. Start with M-x   mx

M-x (that's Alt-x) runs any command by name. That's cool, but what makes it really special is that it lets you auto-complete command names.

Press M-x, type in some input, press TAB (for 'complete this input') and Emacs filters the entire list of commands based on your input:

ask-emacs-mx.webp

There are two important consequences for a beginner:

  1. You never need to memorize a command you can describe. M-x will surface it from a vague memory of what that command looks like.
  2. Each command shows its keybinding (if it has one) next to its name, so M-x doubles as a way to learn 'shortcuts' to invoke these commands.

3. The Help Commands

As promised, Emacs provides commands that let you answer questions about Emacs. These are often called Emacs's 'auto-discovery' commands, and they all start with a few intuitive prefixes:

  • describe- — shows the documentation for a specific named thing (a function, variable, key, or mode).
  • find- — takes you to the source code or definition behind a name.
  • xref- — navigates references and definitions across your code, like "find usages" and "jump to definition."
  • Info- / info- — opens and moves around Emacs's built-in manuals.
  • apropos- — searches by keyword when you don't know the exact name, listing everything that matches.
  • customize- — opens a graphical interface for inspecting and changing settings.

4. The Prefix Trick   discovery

Now that we know M-x and the families of auto-discovery commands, we can leverage M-x to perform something I like to call the 'prefix trick'.

This trick surfaces all Emacs's auto-discovery facilities to you, meaning you don't have to remember the few hundred that exist. Instead you only have to remember the few individual prefixes they all begin with.

For example, every command that describes something (like a command, variable, function, etc…) starts with describe-. So once you know that prefix, you can surface all commands in that family.

Try it. Type M-x describe- and press TAB, and watch all the describe commands surface (see screenshot). You can do this same trick for any of the auto-discovery commands described above.

ask-emacs-describe.webp

The large number of help commands should be an indication of why this trick is useful!

Here are more screenshots for the other prefixes.

4.1. find-

ask-emacs-find.webp

4.2. xref-

ask-emacs-xref.webp

4.3. Info- / info-

ask-emacs-info-cap.webp

ask-emacs-info-low.webp

4.4. apropos-

ask-emacs-apropos.webp

4.5. customize-

ask-emacs-customize.webp

5. C-h C-h Help Cheatsheet   help

C-h (Control-h) is the universal "help" prefix. If you remember one thing from this post, remember C-h C-h — help for help. It opens a buffer listing every kind of help available (see screenshot). You will see the auto-discovery commands described above, as well as some other useful ones. Go explore!

ask-emacs-ch-ch.webp

6. More Magic with which-key

Since Emacs 30, which-key is built into Emacs. Enable it, then type the first part of a keybinding, and you'll see all the commands and their associated keybindings that fall under that prefix key. You even get documentation for the commands in a popup when you mouse over the command names! See the screenshot for this in action with C-h, the help prefix key.

ask-emacs-which-key-ch.webp

Like with C-h C-h, you see all the help commands you can run via the C-h prefix key. Note this works on any prefix key, and even works without a prefix key at all with which-key-show-top-level. In this way, you don't even need to be aware of a prefix key at all, you can discover them all with which-key.

ask-emacs-which-key-top.webp

7. The Coda   emacs

Again, you don't learn Emacs by memorizing stuff. Instead, you learn three things:

  1. M-x to find (and run) commands,
  2. the prefixes of the auto-discovery commands (describe-, find-, xref-, Info- / info-, apropos-, customize-) to enumerate the rest with TAB, and
  3. C-h C-h to find every kind of help

From there, Emacs documents itself, all the way down to its own source code.

Note, this post is the shorter version of a longer, sillier post, with a valuable 'prefix trick' that alleviates the burden of memorizing anything I described in the original post.

-1:-- Emacs Teaches Emacs: The Missing README (Post Charlie Holland)--L0--C0--2026-06-18T21:38:26.000Z

Irreal: The Emacs Help System

Charlie Holland has a very nice contribution to June’s Emacs Carnival about underappreciated Emacs builtins. His post is about the Emacs help system and how you can use it to learn everything about Emacs. It’s a commonplace to say that Emacs is self-documenting but that’s little more than a slogan. Holland takes a long look at what that actually means.

He begins by noting that the help system is self-recursive is the sense that you can ask the help system about the help system. You simply call the help-for-help command intuitively bound to Ctrl+h Ctrl+h. If you’ve never tried it, try it now. It gives you a nice listing of every help command.

Once you invoke help for a certain command or variable, you get a buffer containing a description of the command or variable as well as links to related commands/variables and the source code of the command so you can see exactly what it does and how it does it. You can discover what command a shortcut calls or what the shortcut for a command is with a simple help call.

There are a bunch of other aspects to the help system. You can, for example, get a listing of what your last commands were, complete information about the character at point, the current value of a variable, the current mode, and lots more.

For discovery, there are the apropos command and its siblings to help you find what you’re looking for even if you have no idea of its name. You merely need to have a general description of what it does. Fuzzy completion on command invocation (Meta+x) helps you find the right command even if you have only a vague idea of its name.

Hoplland’s post is long and has a lot of information but it’s one that every Emacs n00b—or more experienced user, for that matter—should read. In Holland’s terminology, it’s the first node in the Emacs knowledge graph.

-1:-- The Emacs Help System (Post Irreal)--L0--C0--2026-06-18T14:28:30.000Z

Rahul Juliato: Emacs 31 Is Around the Corner: The Changes I'm Already Daily Driving

Karthik Chikmagalur recently published another of his excellent "Even More Batteries Included with Emacs" posts, digging into lesser-known features that already ship with Emacs today. I wanted to write its mirror image. His post covers the batteries already in the box. Mine covers the ones arriving in Emacs 31.

Emacs 31 isn't out yet, but I've been building it from both emacs-31 branch and master and daily driving it for months. Every time something new and useful lands, I fold it into Emacs Solo, my no-external-packages config, and mark it with a small ; EMACS-31 comment so I remember to revisit it once the release is official.

This post walks those breadcrumbs. Every change below is one I'm touching in my config right now, with a note on what it does and why I keep it. None of it requires a package. It's all either on master already or close behind.

One disclaimer: Emacs 31 is still in development (actually in pre-release phase), so names and defaults can shift before final release. Everything below is what I'm running as of mid-2026. If you're not building from emacs-31 branch or master, treat this as a preview of what's coming.

Tree-sitter that just works

If I had to pick the single change I'm happiest about, it's this one. For years, getting a *-ts-mode going meant manually populating treesit-language-source-alist, calling treesit-install-language-grammar, and praying your toolchain was set up to compile the grammar. In Emacs 31 a lot of that ceremony goes away:

(treesit-auto-install-grammar 'always) ; EMACS-31
(treesit-enabled-modes t)              ; EMACS-31

treesit-enabled-modes set to t switches the major modes that have a tree-sitter variant over to it, and treesit-auto-install-grammar makes Emacs offer to fetch and build the grammar when it's missing instead of erroring out (more options are available like 'ask and 'ask-dir). This is the treesit-auto package experience, except now the core does the work.

The knock-on effect shows up all over my config. I used to keep lines like these around to teach Emacs where each grammar lives:

(add-to-list 'treesit-language-source-alist
			 '(typescript "https://github.com/tree-sitter/tree-sitter-typescript" "master" "typescript/src"))

In Emacs 31 the grammar sources for languages like TypeScript, TSX, Rust, TOML, YAML and Dockerfile live inside the modes themselves, so I've got a trail of ;; EMACS-31 this is now defined on mode code comments marking every block I get to delete once 31 ships. I'll take less config that does the same job any day.

emacs_31 demo 01

One foot-gun worth flagging if you share your Emacs directory tree across machines of different architectures: the auto-installed grammars are not segregated by architecture. An x86_64 .so and an arm64 one land under the same name, so the binary built on one machine won't load on the other. Something to keep in mind.

There are many more tree-sitter improvements coming to Emacs. The developers have been working tirelessly on it, Yuan Fu, along with many others, have been continuously improving the tree-sitter experience across multiple areas. From better language support to usability and performance enhancements, tree-sitter in Emacs continues to evolve at a remarkable pace.

A built-in markdown-ts-mode (experimental)

Emacs 31 ships a markdown-ts-mode in the box, and this one is close to my heart. I started it. It grew out of a proposal I sent to emacs-devel back in early 2025, where the idea and the first version of the code were mine.

I'd be doing the mode a disservice if I let you think it's a solo effort. Stéphane Marks came along a bit later, rolled up his sleeves, and has since become a co-author of the mode. He's the energy behind much of what makes it nice to use today. He didn't send a patch or two and move on; he stayed, pushing the mode well past what I'd sketched out and sweating the details that turn "it works" into "it's a pleasure." Much of the polish I'm about to brag about is his. The mode is ours now, and it's better for it.

Watching an idea make the round trip from a mailing-list message to core code, and picking up a great collaborator on the way, is one of the most rewarding things about hanging around the Emacs community.

(use-package markdown-ts-mode
  :ensure nil
  :defer t)

It gives you more than colors, and these are the parts I want to show off:

✔️ Org users will feel at home. The keybindings and editing feel stay close to Org: navigating headings, folding sections, moving between structural elements. If your fingers know Org, you won't have to relearn Markdown.

✔️ Live, colored code blocks, even for non-tree-sitter languages. This is my favorite trick. A fenced code block gets fontified using the real major mode for that language, not dumped as flat monospace. It reaches Emacs' own internal modes too, so an ```elisp block lights up with true Emacs Lisp font-locking, and the other built-in modes do the same. You get proper syntax highlighting inside your code samples with no extra setup.

And it's not just colors: the code-block editing commands largely work too, so you can edit a fenced block with the target language's mode rather than fighting plain text. Completion inside blocks is still the rough spot, that infrastructure is wonderfully twisty and we haven't fully cracked it yet, so if you go poking, that's where the bugs hide.

✔️ Inline image viewing. Image links render in the buffer, so a Markdown doc with screenshots or diagrams reads like a document, not a wall of ![](path) noise.

And many more features discoverable and being developed.

Together these make it feel like a comfortable place to write and read Markdown inside Emacs, not a syntax highlighter bolted onto .md files.

One caveat I want to be upfront about: markdown-ts-mode is still experimental, and you have to opt into it. As the header of markdown-ts-mode.el notes, it isn't wired up to auto-mode-alist yet, so it won't take over .md files on its own. For now you pull in the library with M-x load-library RET markdown-ts-mode, then turn it on in a bufferf, or add it to auto-mode-alist yourself if you're feeling brave.

Stéphane and I are working to get it considered ready by the next Emacs release, and that's where you come in. If you try it and hit rough edges, or it works great, we want to hear about it. Send feedback to the bug list with M-x report-emacs-bug, or reach out to me and Stéphane directly. Real-world use is what moves a mode from "experimental" to "done", so don't be shy.

emacs_31 demo 02

Many more screenshots here.

Eglot rendering docs with markdown-ts (also, still experimental)

Speaking of Markdown, Eglot in Emacs 31 can render LSP documentation using that same internal mode instead of falling back to plain text:

(eglot-documentation-renderer 'markdown-ts-view-mode) ;; EMACS-31
(eglot-code-action-indications nil)                   ;; EMACS-31

markdown-ts-view-mode gives you formatted hover docs without pulling in anything extra. The same experimental caveat applies here, since it leans on markdown-ts-mode, so treat it as something to opt into rather than a finished default. I also turn off eglot-code-action-indications. The new inline "you can do a code action here" hints are clever, but some language servers make them noisy, so I keep them off.

emacs_31 demo 03

There's also some churn here: eglot-events-buffer-size is on its way out in favor of eglot-events-buffer-config, so I've left a ;; EMACS-31 -- do we still need it? note on the old variable to clean up later.

eldoc at point

A small one I'm fond of:

(eldoc-help-at-pt t) ;; EMACS-31

With this on, eldoc shows the help text for whatever sits under the cursor, without me invoking anything. Paired with eldoc-echo-area-prefer-doc-buffer, it makes wandering through unfamiliar code feel more guided.

Smarter, eager completion

The minibuffer and completion machinery picked up a few new toggles:

(completion-eager-update t)               ;; EMACS-31
(completion-eager-display 'auto)          ;; EMACS-31
(minibuffer-visible-completions 'up-down) ;; EMACS-31

completion-eager-update and completion-eager-display refresh the completion UI as you type instead of waiting for you to ask. If you don't run something like icomplete, setting eager display to t gives you a sharp out-of-the-box experience on its own. And minibuffer-visible-completions set to 'up-down lets you move through the visible candidates with the arrow keys, which feels natural at last.

icomplete got attention too, and this is another one I had a direct hand in. Emacs 31 includes the patch from bug#75784, which I proposed and worked on. It brings vertical in-buffer behavior and prefix indicators to icomplete. The side effect I like: a big compatibility block I'd been carrying in my config can finally go away:

(when (and (>= emacs-major-version 31)
		   (boundp 'icomplete-vertical-in-buffer-adjust-list))
  (setq icomplete-vertical-in-buffer-adjust-list t)
  (setq icomplete-vertical-render-prefix-indicator t))

Window layout gymnastics

This is a fun set of new commands for rearranging your window layout without manually splitting and killing windows:

("C-x w t"   . window-layout-transpose)        ; EMACS-31
("C-x w r"   . window-layout-rotate-clockwise) ; EMACS-31
("C-x w f h" . window-layout-flip-leftright)   ; EMACS-31
("C-x w f v" . window-layout-flip-topdown)     ; EMACS-31

Transpose swaps your horizontal and vertical arrangement, rotate spins the whole layout around, and the flip commands mirror it left-to-right or top-to-bottom. If you've ever built a three-window layout and then wished the editor pane were on the other side, these do the job and keep every buffer in place while they're at it.

A Speedbar that lives in a side window

Speedbar has been around forever, but in Emacs 31 it learned to live in a proper side window instead of a separate frame:

(speedbar-window-default-width 25) ;; EMACS-31
(speedbar-window-max-width 25)     ;; EMACS-31

;; bound to M-I in my config:
(speedbar-window) ;; EMACS-31

speedbar-window docks it to the side like a modern file tree. On a tiling setup or a single-monitor laptop, that beats the old floating-frame behavior by a mile. A width cap keeps it from fighting my other windows.

emacs_31 demo 04

VC niceties

A few version-control improvements I've happily turned on:

(setopt
 vc-auto-revert-mode t                    ; EMACS-31
 vc-allow-rewriting-published-history t   ; EMACS-31
 vc-dir-auto-hide-up-to-date 'revert)     ; EMACS-31

vc-dir-auto-hide-up-to-date is the one I'm most pleased about. Refreshing a vc-dir buffer now hides the up-to-date files on its own, so I no longer need my g-key hack that called vc-dir-refresh followed by vc-dir-hide-up-to-date. Another block marked for deletion. vc-allow-rewriting-published-history nods to workflows like Jujutsu and force-pushing feature branches, where rewriting already-pushed history is a deliberate move.

Editable xref buffers

This one isn't a variable, it's a comment in my config reminding me to remove a custom hack:

;; EMACS-31 Remove this, since new emacs will come with 'e' for editing xref buffers.
;; Reference: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=80616

I'm going to indulge myself and tell the longer version of this one, because I was part of it and it shows how features find their way into Emacs.

The itch was this. Both Dired and grep buffers have long had an "edit" workflow. In Dired you toggle into wdired-mode; in a grep buffer you press e for grep-edit-mode. Bulk renaming and bulk search-and-replace feel natural there. Xref buffers had no such thing. The only editing operation was r (xref-query-replace-in-results), which is regex-only and won't let you edit individual lines. I lean hard on project.el and xref for navigating and refactoring, and I kept catching myself re-running the same search with M-x grep to get an editable buffer. An annoying detour, since xref already held all the information needed.

So in March 2026 I sent a patch to bug-gnu-emacs proposing a small command, xref-export-to-grep, bound to E in *xref* buffers. It re-fetched the xref items, formatted them as file:line:content, and dropped them into a grep-mode buffer where you could press e and edit as usual. Nothing fancy. It bridged two things that already existed, and I'd carried it as a personal snippet for a while.

What happened next is the part I love about this community. Dmitry Gutov, who maintains xref, looked at it and pushed back on the UI of my approach. My command created a hop between buffers, and once you landed in the grep buffer you still had to know which key to press. He asked a sharper question than the one I'd answered: did I care about the grep export, or would it be better if xref buffers let you edit inline?

That reframing was right. I told him I had no attachment to the grep detour. Inline editing in the xref buffer itself, with multi-line edits across matches, would kill the whole roundtrip. A few days later he'd written and pushed xref-edit-mode. It drops the extra step and runs faster on large xref buffers. My original xref-export-to-grep could still go in as an optional command without a default binding, but the inline mode is the better answer and it's what I use now.

The thread didn't stop there. It spun off into a wider design chat with Juri Linkov about the *-edit-mode family (occur/grep/xref, which write each buffer normally) versus wdired's queue-everything-then-C-x C-s model, and whether a future "live" search UI might present results differently. For the record, here's the safety net I mentioned in that thread, a trick I picked up from Protesilaos that lets me hit d to diff a buffer against its file before saving during save-some-buffers:

(add-to-list 'save-some-buffers-action-alist
			 (list "d"
				   (lambda (buffer)
					 (diff-buffer-with-file (buffer-file-name buffer)))
				   "show diff between the buffer and its file"))

Back to the topic, the end result: Emacs 31 ships editable xref buffers, my config drops a homegrown workaround, and the feature that landed beats the one I proposed, because the maintainer asked the right question. Getting to play a small part in that loop is a big chunk of why I enjoy living on master. The full back-and-forth is public in bug#80616 if you're curious.

So, if you would like to try it. After C-x p g, grep for something like FontAwesomeIcon. Now e starts the edit mode, make your edits, C-c C-c to confirm.

emacs_31 demo 05

ERC gets tidier

A couple of IRC improvements, since I live in ERC:

(erc-log-insert-log-on-open 'erc-log-new-target-buffer-p) ;; EMACS-31

This makes ERC insert prenvious logs only for newly opened target buffers, the behavior I want when rejoining channels. And one of my favorite small fixes: in Emacs 31 the scrolltobottom module no longer depends on erc-fill-wrap, so I can drop the conditional that used to add it by hand for older versions. Thank you to whoever untangled that.

The grab bag of quality-of-life knobs

And then there's the long tail of tiny improvements that don't each deserve a section but absolutely earn their place:

(delete-pair-push-mark t)                    ; EMACS-31: pushes a mark after
											 ; delete-pair so C-x C-x selects what was inside
(ibuffer-human-readable-size t)              ; EMACS-31: KB/MB instead of raw byte counts
(ielm-history-file-name ...)                 ; EMACS-31: IELM input history is finally persisted
(kill-region-dwim 'emacs-word)               ; EMACS-31: C-w with no region kills a word
(native-comp-async-on-battery-power nil)     ; EMACS-31: stop native-comp jobs on battery
(view-lossage-auto-refresh t)                ; EMACS-31: live-updating C-h l, great for teaching/debugging
(display-fill-column-indicator-warning nil)  ; EMACS-31
(dired-hide-details-hide-absolute-location t); EMACS-31: hide the absolute dir path in dired-hide-details-mode
(world-clock-sort-order "%FT%T")             ; EMACS-31: sort the world clock sanely
(zone-all-frames t)                          ; EMACS-31
(zone-all-windows-in-frame t)                ; EMACS-31
(uniquify-after-kill-buffer-flag t)          ; EMACS-31: renamed from the -p variant

A few of these are worth a sentence:

✔️ kill-region-dwim fixes a decades-old papercut. Set it to 'emacs-word and hitting C-w with no active region kills a word backwards instead of signalling an error. No more "the mark is not active" interruptions.

✔️ view-lossage-auto-refresh turns C-h l into a live view of your last keystrokes. When I'm screen-sharing or teaching, people can watch the keys I press in real time.

✔️ ielm-history-file-name lets my IELM scratch sessions survive a restart, the way comint and the shell already do.

✔️ native-comp-async-on-battery-power nil saves the laptop: no surprise fan spin-ups from background native compilation while I'm unplugged on a train.

✔️ tty-tip-mode brings tooltips to the terminal, a nice touch for those of us who run Emacs in -nw.

Honorable mention: term stops eating lines

This one gets no config line, because there's nothing to configure. A bug got fixed, and it makes me happier than it has any right to.

For a long time, term (and ansi-term) had a nasty habit of swallowing lines. Full-screen, cursor-addressing programs left the display garbled, with rows eaten or misplaced as the program redrew. That hit the exact programs you most want a real terminal for: htop, nethack, anything curses-based was close to unusable inside Emacs' terminal.

Emacs 31 fixes it. term redraws correctly now, and I can run htop to watch processes or fire up nethack for a "quick" break without the buffer turning into confetti. It sounds small, and it removes one of the last reasons I had to reach for an external terminal emulator.

emacs_31 demo 06

emacs_31 demo 07

Honorable mention 2: Modus 5 themes!

Thanks to Protesilaos, Emacs now ships with several modus themes:

✔️ modus-operandi-deuteranopia -- Deuteranopia-optimized theme with a white background.

✔️ modus-operandi -- Elegant, highly legible theme with a white background.

✔️ modus-operandi-tinted -- Elegant, highly legible theme with a light ochre background.

✔️ modus-operandi-tritanopia -- Tritanopia-optimized theme with a white background.

✔️ modus-vivendi-deuteranopia -- Deuteranopia-optimized theme with a black background.

✔️ modus-vivendi -- Elegant, highly legible theme with a black background.

✔️ modus-vivendi-tinted -- Elegant, highly legible theme with a night sky background.

✔️ modus-vivendi-tritanopia -- Tritanopia-optimized theme with a black background.

Why bother running master?

People ask why I daily drive an unreleased Emacs. Same reason I run a no-packages config: I want to know what's in the box, and the way to learn what's coming is to live in it. Most of these changes are small, yet they add up to an editor that needs less of my glue code each release. Watching my config get shorter as the core absorbs things I used to hand-roll is one of the quiet joys of being an Emacs user.

For the other side of this coin, the batteries already there waiting to be found, go read Karthik's post. It's a great companion to this one. And to see every snippet above in context, they're all in the Emacs Solo init.el, each marked with that small ; EMACS-31 breadcrumb.

See you when 31 ships, at which point I get to go delete a pile of code. Happy hacking.

Edit

2026-06-29: Updated treesit-auto-install-grammar to 'always.

2026-06-18: Thanks to Stéphane Marks for the careful read and corrections. He flagged the tree-sitter architecture foot-gun for shared config directories (now noted above), pointed out that markdown-ts-mode's code-block editing commands work and not just the highlighting, and caught that the VC variable is now vc-dir-auto-hide-up-to-date, not the name I'd written.

-1:-- Emacs 31 Is Around the Corner: The Changes I'm Already Daily Driving (Post Rahul Juliato)--L0--C0--2026-06-18T03:41:00.000Z

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: Emacs Chat 26: Ross A. Baker

I chatted with Ross Baker about Emacs (including running Emacs 28), his Emacs config, and life.

I'll update this blog post with the transcript. 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

Chapters

  • 0:00 Opening
  • 0:46 What Ross does
  • 2:06 How Ross got into Emacs, used other editors, and then came back to Emacs
  • 4:58 Config focusing on built-ins
  • 10:12 simple-orderless
  • 14:29 Size indicator
  • 16:40 graceful degradation
  • 17:49 emacs-lock-mode
  • 19:52 exiting Emacs: yes-or-no-p
  • 22:18 Moving keymaps
  • 23:54 Org Mode more for writing, Markdown; ox-hugo includes barbecue recipes posting
  • 24:23 Writing in Org Mode and Markdown
  • 27:50 Ethersync?
  • 29:16 Managing Github with Forge
  • 35:49 Committing with work addresses vs personal
  • 37:13 Emacs tinkering as stress relief
  • 41:06 Under-appreciated Emacs built-ins
  • 42:20 gptel
  • 46:04 Getting older
  • 49:51 Nix is good at managing package versions and customizing them; Matthew Bauer (Bauer IDE)
  • 53:25 Custom fonts
  • 55:34 Nix vs Guix; Mac
  • 56:26 Non-work interests: Org for documenting; ox-hugo and multiple languages

Chat

  • Ray-On-Emacs: ​​How do you exit Emacs, then? Or do you never exit Emacs?
  • pratikmishra4073: ​i stealing that lock mode hack. i too have killed scratch buffer accidentally before.
  • ispringle: ​`(global-set-key (kbd "C-c l") #'emacs-lock-mode)` is handy for one off locks too
  • PuercoPop: ​​There is a gh-notify package specifically for high volume GitHub notifications
  • blaiseutube: ​​I keep procrastinating my return to emacs 😔
  • gr1maldi: ​​Yo, and stuff. Sorry I'm late.
  • Ray-On-Emacs: ​​Getting older! Oh boy! more tell me, please
  • dubstepandlovee: ​​fantastic chat so far! as a local agent user, gptel-agent looks like an interesting project
  • Trevoke: ​​Hopefully without starting a philosophical war, why nix over guix?
  • dubstepandlovee: ​why nix over lix
  • dubstepandlovee: ​(joke)
  • Trevoke: ​​shakes fist in F/OSS Thanks for the answer
  • blaiseutube: ​​recovering linguist here. English Spanish and French for work. Japanese Portuguese, Sanskrit and Swedish for fun.
  • blaiseutube: ​​c-x h ? I love it
  • sachactube: ​​Maybe C-x 8 RET
  • blaiseutube: ​oh! thank you
  • Ray-On-Emacs: Thank you!
View Org source for this post

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

-1:-- Emacs Chat 26: 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

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!