Rahul Juliato: Taming Emacs Cache and Temporary Files

You open your favorite editor, and, out of the box, Emacs writes state files all over the place. It puts bookmarks in ~/.emacs.d/, drops #auto-saves# next to every file you edit, leaves .~lockfiles~ in your projects, scribbles recentf, history, saveplace, projects, transient/history.el, tramp, network-security.data, multisession/, url/, image-dired/, erc/, rcirc/... you get the picture. The features are great, don't get me wrong. The default locations are what annoy me.

Most of those files are not noise. They are the state that makes Emacs feel like Emacs across restarts. So you cannot just delete them. But you also do not want them spread across N different directories with cryptic names. (I know I don't.)

I want one directory I control, every cache-bound variable pointing inside it, and a switch to flip it between "persistent inside my config" and "ephemeral in /tmp". No external package, no naming scheme to memorize, just a small pattern I can read top to bottom in init.el.

My emacs-solo config used to hard-code a single relative path under user-emacs-directory for all these cache files. It worked, but it was inflexible. A user opened an issue asking if the cache location could be changed without forking the config, since they wanted those files somewhere else entirely. So I redesigned it around a defcustom root and an alist of relative paths, switchable through M-x customize. The version below is the same idea with the emacs-solo names dropped.


Our goal

Patch these three pieces:

cache directory: holds every piece of mutable state Emacs writes during a session.

alist map: lists every variable that needs to be pointed at that directory.

helpers: one resolve a key to an absolute path, and another pre-creates every directory so we never get "no such file or directory" warnings at startup.

In practice, a .emacs.d directory ends up looking like this:

.
├── cache
│   ├── auto-saves
│   ├── erc
│   ├── image-dired
│   ├── multisession
│   ├── rcirc
│   ├── transient
│   ├── url
│   └── ...
├── eln-cache
│   └── 32_0_50-25c5b284
├── eshell
│   └── history
├── init.el
└── tree-sitter
	├── libtree-sitter-markdown-inline.dylib
	└── libtree-sitter-markdown.dylib

Our switchable base directory

Start with a defcustom for the root. Using defcustom (instead of defvar) lets you change the value through M-x customize without editing init files, and the choice persists in custom.el:

(defcustom my/cache-directory
  (expand-file-name "cache/" user-emacs-directory)
  "Base directory for Emacs cache files.
All entries in `my/cache-paths' are resolved relative to this
directory.  Choose one of the presets or supply any custom path.
Changes take effect after restarting Emacs."
  :type `(choice
		  (const     :tag "Inside Emacs config  (cache/ in user-emacs-directory)"
					 ,(expand-file-name "cache/" user-emacs-directory))
		  (const     :tag "System temp          (/tmp/emacs-cache/)" "/tmp/emacs-cache/")
		  (directory :tag "Custom directory"))
  :group 'my)

The default puts everything under ~/.emacs.d/cache/, which keeps the rest of ~/.emacs.d/ clean and lets you back up or delete the whole cache as one directory. The /tmp/ preset is for sessions that should leave no trace. The directory choice lets you point at any custom path.

I use user-emacs-directory instead of a literal ~/.emacs.d/ because Emacs 29 added the --init-directory flag, which lets you launch Emacs against any config directory. I use it constantly to try other people's configs side by side with my own without touching ~/.emacs.d/. Anchoring on user-emacs-directory means the cache follows whichever config Emacs was started with, instead of every alternate config writing into the default ~/.emacs.d/ and stepping on each other.

In my early-init.el I already load custom-file, but I reload it here too. customize writes its changes to custom.el immediately, so if you change the cache directory mid-session through M-x customize and then restart, you want the new value to apply before the rest of init.el runs and calls my/cache--path:

(when custom-file
  (load custom-file 'noerror 'nomessage))

The when guard is there because in a brand-new config custom-file is nil, and (load nil 'noerror 'nomessage) signals (wrong-type-argument stringp nil) and aborts the rest of init.el. The 'noerror flag suppresses file-error, not type errors.

This whole reload is a bit of a hack. Loading custom-file twice during startup just to get a defcustom value hot before the next form is not what Emacs intends. It only matters the first time you switch presets. Without it, you would wonder why your new /tmp/emacs-cache/ is empty while your old ~/.emacs.d/cache/ keeps receiving writes.


Our single alist as the source of truth

The next piece is the mapping from keys to relative paths.

How you organize this alist is your call. The list below is what I wire through my/cache-path in my own config, but plenty of users will split things differently. I deliberately keep tree-sitter/, eln-cache/, and eshell/ outside this alist. tree-sitter and eln-cache are populated by long-running, expensive processes (grammar compilation, native compilation) that I want to survive when I reset my cache, so they live next to the config under user-emacs-directory directly. eshell carries my command history and aliases, which I treat more like dotfiles than throwaway state. Your workflow will pull these differently, and that is fine.

(defvar my/cache-paths
  '(;; Files:
	(bookmark-file               . "bookmarks")
	(ielm-history-file-name      . "ielm-history.eld")
	(project-list-file           . "projects")
	(recentf-save-file           . "recentf")
	(savehist-file               . "history")
	(save-place-file             . "saveplace")
	(transient-history-file      . "transient/history.el")
	(transient-levels-file       . "transient/levels.el")
	(transient-values-file       . "transient/values.el")
	(tramp-persistency-file-name . "tramp")
	(nsm-settings-file           . "network-security.data")
	;; Directories:
	(auto-saves                  . "auto-saves/")
	(auto-saves-sessions         . "auto-saves/sessions/")
	(multisession-directory      . "multisession/")
	(url-configuration-directory . "url/")
	(image-dired-dir             . "image-dired/")
	(erc-log-channels-directory  . "erc/logs/")
	(erc-image-cache-directory   . "erc/images/")
	(rcirc-log-directory         . "rcirc/logs/"))
  "Alist of (KEY . RELATIVE-PATH) for cache locations.
RELATIVE-PATH is resolved against `my/cache-directory'.
A trailing slash on RELATIVE-PATH marks the entry as a directory.")

The convention I follow: keys are usually the names of the Emacs variables they will fill. That keeps grep useful for both the definition and the usage.

A trailing slash on the value marks a directory (this matches directory-name-p in Emacs). No trailing slash means a file. The next helper uses that distinction.


Our helpers

The first helper turns a key into an absolute path:

(defun my/cache--path (key)
  "Return the absolute path for KEY in `my/cache-paths'."
  (let ((rel (cdr (assq key my/cache-paths))))
	(unless rel
	  (error "my/cache--path: Unknown key %S" key))
	(expand-file-name rel my/cache-directory)))

assq does an eq lookup on symbol keys. The unless rel branch is there because typos in :custom blocks are silent otherwise: you would get nil and Emacs would happily write to nil, which fails in confusing ways. Better to error at config load.

The second helper pre-creates every directory the alist mentions, so we never get "directory does not exist" warnings from packages on first run:

(defun my/cache--ensure-dirs ()
  "Create every directory referenced by `my/cache-paths'.
Entries ending in `/' are created directly; other entries have their
parent directory created."
  (dolist (entry my/cache-paths)
	(let* ((abs (my/cache--path (car entry)))
		   (dir (if (directory-name-p abs)
					abs
				  (file-name-directory abs))))
	  (make-directory dir t))))

(my/cache--ensure-dirs)

If the entry is a directory (directory-name-p returns t for values ending in /), it is created as-is. If the entry is a file, only the file's parent directory is created.

The t argument to make-directory is the "parents" flag, the equivalent of mkdir -p. So transient/history.el correctly creates <cache>/transient/ even though we never list it explicitly.


Wiring it into use-package :custom

Now every cache-bound variable points at our helper. Inside a use-package emacs block (or wherever you set built-ins):

(use-package emacs
  :ensure nil
  :custom
  (bookmark-file              (my/cache--path 'bookmark-file))
  (ielm-history-file-name     (my/cache--path 'ielm-history-file-name))
  (project-list-file          (my/cache--path 'project-list-file))
  (recentf-save-file          (my/cache--path 'recentf-save-file))
  (savehist-file              (my/cache--path 'savehist-file))
  (save-place-file            (my/cache--path 'save-place-file))
  (transient-history-file     (my/cache--path 'transient-history-file))
  (transient-levels-file      (my/cache--path 'transient-levels-file))
  (transient-values-file      (my/cache--path 'transient-values-file))
  (nsm-settings-file          (my/cache--path 'nsm-settings-file))
  (multisession-directory     (my/cache--path 'multisession-directory))
  (url-configuration-directory (my/cache--path 'url-configuration-directory))
  ;; The two below are *not* backups; they keep auto-save state
  ;; without scattering `#file#' next to every edited buffer.
  (create-lockfiles  nil)   ; no `.#file' lock files at all
  (make-backup-files nil)   ; no `file~' tilde backups at all
  (auto-save-default t))    ; auto-save *is* kept, just redirected below

On the three settings at the bottom:

create-lockfiles nil and make-backup-files nil are personal taste. Lockfiles warn another Emacs not to clobber your buffer, but they break frontend tooling that watches directories for changes (TypeScript, Vite, esbuild). The tilde backups I find redundant with modern VCS and auto-save.

auto-save-default t stays on because auto-save is what rescues you when Emacs crashes. We just want it somewhere else.


Redirecting auto-saves

Auto-save needs two extra settings because Emacs uses path transforms for it instead of single-value variables:

;; We want auto-save, but no #file# cluttering, so everything goes
;; under our cache/ tree. Directories are pre-created.
(setq auto-save-list-file-prefix (my/cache--path 'auto-saves-sessions)
	  auto-save-file-name-transforms
	  `((".*" ,(my/cache--path 'auto-saves) t)))

auto-save-list-file-prefix controls where the "list of files with pending auto-saves" lives. This is what M-x recover-session reads. Pointing it at our auto-saves/sessions/ directory means you can still recover after a crash, without ~/.emacs.d/auto-save-list/ cluttering your config.

auto-save-file-name-transforms is a list of (REGEX REPLACEMENT UNIQUIFY) triples. The t at the end is the uniquify flag, which encodes the original path into the filename so two files with the same name in different directories do not collide in the auto-save folder.

Both end up in <cache>/auto-saves/.


TRAMP, viper, and other late bindings

Some variables are not safely set in :custom, because they are defined inside packages that load later. For those, use setopt (which respects defcustom setters) inside the :config block:

(setopt tramp-persistency-file-name (my/cache--path 'tramp-persistency-file-name))
(setopt viper-custom-file-name      (my/cache--path 'viper-custom-file-name))

setopt is the modern equivalent of setq for customizable variables. It runs any :set function the variable defines, which tramp-persistency-file-name does (it triggers a reload). Plain setq would skip that and leave TRAMP confused.


What you get

~/.emacs.d/cache/ (or wherever you point it) contains everything. du -sh tells you how much state Emacs is hoarding. rm -rf resets it all without touching your config.

M-x customize-variable RET my/cache-directory lets you flip between persistent and ephemeral modes without editing init files. Useful for screencasts where you want zero history showing, or for testing whether a problem is config or state.

New packages are a two-line change. When you adopt, say, newsticker, you add one entry to my/cache-paths and one (my/cache--path 'newsticker-dir) line in the package's :custom. The directory is auto-created on next restart.

You can grep for it. grep my/cache--path init.el lists every place Emacs writes state, and the alist tells you what kind.


The complete code

Here is everything in one block. Copy this into some temporary folder inside the init.el file. After that, cd into this temp directory and run emacs --init-directory=./. You can them navigate files, use Emacs features and check where the created files end up to.

(defcustom my/cache-directory
  (expand-file-name "cache/" user-emacs-directory)
  "Base directory for Emacs cache files."
  :type `(choice
		  (const     :tag "Inside Emacs config  (cache/ in user-emacs-directory)"
					 ,(expand-file-name "cache/" user-emacs-directory))
		  (const     :tag "System temp          (/tmp/emacs-cache/)" "/tmp/emacs-cache/")
		  (directory :tag "Custom directory"))
  :group 'my)

(when custom-file
  (load custom-file 'noerror 'nomessage))

(defvar my/cache-paths
  '(;; Files:
	(bookmark-file               . "bookmarks")
	(ielm-history-file-name      . "ielm-history.eld")
	(project-list-file           . "projects")
	(recentf-save-file           . "recentf")
	(savehist-file               . "history")
	(save-place-file             . "saveplace")
	(transient-history-file      . "transient/history.el")
	(transient-levels-file       . "transient/levels.el")
	(transient-values-file       . "transient/values.el")
	(tramp-persistency-file-name . "tramp")
	(nsm-settings-file           . "network-security.data")
	;; Directories:
	(auto-saves                  . "auto-saves/")
	(auto-saves-sessions         . "auto-saves/sessions/")
	(multisession-directory      . "multisession/")
	(url-configuration-directory . "url/")
	(image-dired-dir             . "image-dired/")
	(erc-log-channels-directory  . "erc/logs/")
	(erc-image-cache-directory   . "erc/images/")
	(rcirc-log-directory         . "rcirc/logs/"))
  "Alist of (KEY . RELATIVE-PATH) for cache locations.")

(defun my/cache--path (key)
  "Return the absolute path for KEY in `my/cache-paths'."
  (let ((rel (cdr (assq key my/cache-paths))))
	(unless rel
	  (error "my/cache--path: Unknown key %S" key))
	(expand-file-name rel my/cache-directory)))

(defun my/cache--ensure-dirs ()
  "Create every directory referenced by `my/cache-paths'."
  (dolist (entry my/cache-paths)
	(let* ((abs (my/cache--path (car entry)))
		   (dir (if (directory-name-p abs)
					abs
				  (file-name-directory abs))))
	  (make-directory dir t))))

(my/cache--ensure-dirs)

(use-package emacs
  :ensure nil
  :custom
  (bookmark-file               (my/cache--path 'bookmark-file))
  (ielm-history-file-name      (my/cache--path 'ielm-history-file-name))
  (project-list-file           (my/cache--path 'project-list-file))
  (recentf-save-file           (my/cache--path 'recentf-save-file))
  (savehist-file               (my/cache--path 'savehist-file))
  (save-place-file             (my/cache--path 'save-place-file))
  (transient-history-file      (my/cache--path 'transient-history-file))
  (transient-levels-file       (my/cache--path 'transient-levels-file))
  (transient-values-file       (my/cache--path 'transient-values-file))
  (nsm-settings-file           (my/cache--path 'nsm-settings-file))
  (multisession-directory      (my/cache--path 'multisession-directory))
  (url-configuration-directory (my/cache--path 'url-configuration-directory))
  (create-lockfiles            nil)
  (make-backup-files           nil)
  (auto-save-default           t)
  :config
  (setq auto-save-list-file-prefix (my/cache--path 'auto-saves-sessions)
		auto-save-file-name-transforms
		`((".*" ,(my/cache--path 'auto-saves) t)))
  (setopt tramp-persistency-file-name (my/cache--path 'tramp-persistency-file-name)))

Adapt the alist to the packages you actually use.


Other Resources

If you want to read more on the topic:

https://www.gnu.org/software/emacs/manual/html_node/emacs/Auto-Save-Files.html

https://www.gnu.org/software/emacs/manual/html_node/elisp/Variable-Definitions.html#index-defcustom

If you would rather install a package than maintain your own alist, the no-littering package is a popular ready-made alternative that covers a wide set of variables out of the box.

The version of this code I actually run, alist entries and all, lives in my emacs-solo config under the CACHE PATHS heading of init.el. If you end up adapting this for your own setup, I would love to hear which variables you added that I forgot.

-1:-- Taming Emacs Cache and Temporary Files (Post Rahul Juliato)--L0--C0--2026-05-22T16:46:00.000Z

Amin Bandali: ffs 0.2.2 released

ffs provides a minor mode for simple plain text presentations in Emacs, where the slides are separated using the page-delimiter, by default the form feed character (^L).

I wrote ffs in early 2022 for my LibrePlanet 2022 presentation the Net beyond the Web, and earlier this year decided to polish it towards being a proper package and submit it to GNU ELPA. The manual still needs some more work, but the overall package is in pretty good shape so I submitted for inclusion in GNU ELPA.

ffs and I owe a debt of gratitude to Protesilaos for rounds of code review and feedback for improving and polishing the package in preparation for submission to GNU ELPA. You can watch videos of these sessions posted earlier on my website:

Further, inspiration for parts of ffs's implementation was gratefully drawn from Protesilaos's Logos package for Emacs.

Dedicated to the loving memory of Farangis Yousefinia.

Below are the release notes.


Version 0.2.2 on 2026-05-21

First release of ffs on GNU ELPA.

The attempted build of ffs 0.2.1 within GNU ELPA build sandbox failed with an Error: void-function (org-texinfo-kbd-macro) due to use of #+macro: kbd (eval (org-texinfo-kbd-macro $1)) in ffs.org for better formatting of key sequences in the exported Texinfo copy. This seems to have happened for the specific case of generating a plain text README using ox-ascii where ELPA didn't load ox-texinfo. To try and mitigate this, a README.md has been added for use as the package README instead of ffs.org. If not sufficient, a Texinfo copy of the ffs manual will be shipped instead of the Org one in the next release.

ffs 0.2.2 also includes small fixes and improvements throughout ffs.el from Stefan Monnier, and additional feedback to be addressed in future releases.

Version 0.2.1 on 2026-05-20

The attempted build of ffs 0.2.0 within GNU ELPA build sandbox failed with a "Cannot include file" error on the "#+include: fdl.org" in the manual. So, as a workaround, we switch to using the official Texinfo copy of the GNU FDL license rather than an Org copy.

Version 0.2.0 on 2026-05-19

First release of ffs intended for GNU ELPA.

After a few years of inactivity, in early 2026 I decided to dust off ffs.el, polish and document it, and offer for inclusion in GNU ELPA as a proper package.

Default value of ffs-default-face-height changed to nil

To minimize unexpected and/or unnecessary changes out-of-the-box, the default value of ffs-default-face-height has been changed to nil.

ffs-edit-buffer-name demoted from user option to variable

This is not an important user-facing setting, so to help avoid overwhelming users with many options, this has been demoted from a user option to a variable.

Several new user options for customizing ffs's behaviour

As part of the effort to bring ffs more in line with the conventions of other existing Emacs packages, the mechanisms for toggling various parts of Emacs's interface to minimize visual clutter were changed from being minor modes to being customizable user options. These are the replacement new user options, with a default value of nil:

  • ffs-hide-cursor
  • ffs-hide-mode-line
  • ffs-hide-header-line

Their value is buffer-local, and may be set globally using setq-default. See the sample configuration in the manual for an example of how to customize them.

The new ffs-page-delimiter user option defines the page delimiter inserted by ffs-edit-done when inserting a new slide. Emacs's page-delimiter regexp should be able to match ffs-page-delimiter's value, so if you use a custom page-delimiter be sure to customize ffs-page-delimiter accordingly.

The new ffs-echo-progress user option controls whether to display in echo area the progress through the slides. When non-nil, changing slides will also display the progress through the slides in the echo area. The format of the displayed progress can be customized using the new ffs-echo-progress-format user option.

The new ffs-edit-display-buffer-alist user option may be used to control the Window configuration for the ffs-edit buffer. By default, it will display the ffs-edit buffer in the same window.

The new ffs-edit-done-hook user option may be used to define hooks to be run at the end of ffs-edit-done after returning to the main ffs presentation buffer.

Lastly, a new ffs-find-speaker-notes-function variable was added to allow customizing the find function used for opening the speaker's notes file, defaulting to find-file-other-frame.

Version 0.1.0 on 2022-05-19

Initial publication of ffs.el as part of my personal configurations for GNU Emacs.

My first attempt at this concept was a now-archived ffsanim.el, a major mode implementation that used Emacs's animate library to animate slide texts onto the screen. Shortly after realizing the shortcomings of that approach, I abandoned it in favour a minor mode implementation and published version 0.1.0 of what is now ffs in my personal configs repository.

I used this implementation for presenting my LibrePlanet 2022 talk, The Net beyond the Web.

I picked "ffs" as the package name, the acronym for form feed slides.

-1:-- ffs 0.2.2 released (Post Amin Bandali)--L0--C0--2026-05-21T21:33:33.000Z

Irreal: Annotate In Place

Charlie Holland has a very interesting post about annotation in place. The idea is to take notes on digital content the same way you would if your were marking up a book or a physical paper. The important thing is that you don’t want to suffer a context switch disruption by switching to another app to take your notes and you want those notes to appear (even years later) when you revisit the file. A secondary consideration is that you want to be able to go not only from the text to the notes but also from the notes to the text.

There is—as we Emacsers always say—an Emacs package for that. That package is org-remark. It does its magic just as you’d expect. The notes are anchored in the text by highlighting the passage you’re writing about and the position of that highlight and its associated notes are kept in a separate Org file with enough meta data to get back to the original document.

The package comes with builtin support for several document types but Holland says that it’s pretty easy to add others and that in fact he’s added them for Elfeed, PubMed, and Wombag. The major shortcoming that I can see is that PDFs aren’t supported.

Holland’s post includes an 18 minute, 15 second video that demonstrates org-remark and provides a nice overview of the post. The post itself is long and comprehensive.

The org-remark package seems like a nice app that could be a big help for those of us that like to take notes as we’re reading. I could see myself using it to take notes on Web pages that I want to write about for Irreal. If it seems like it might be useful to you, take a look at Holland’s post.

Update [2026-05-21 Thu 13:48]: Added link to Holland’s post.

-1:-- Annotate In Place (Post Irreal)--L0--C0--2026-05-21T15:01:05.000Z

Sacha Chua: Emacs Chat 23: Emacs Chat with Raymond Zeitler

I chatted with Raymond Zeitler about Emacs, life, automation, Org Mode, Diary, and Calendar. There were a couple of cuts to get rid of accidentally shown passwords, but it was a great glimpse into someone's system for managing things.

View in the Internet Archive, watch or comment on YouTube, read the transcript online, download the transcript, download the audio, or email me.

Related links:

You can add the iCal for upcoming Emacs Chat episodes to your calendar. https://sachachua.com/topic/upcoming-emacs-chats.ics

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

Chapters:

  • 0:00 Opening
  • 0:58 Introduction
  • 1:59 I love automating workflows
  • 3:15 Org Mode switch
  • 4:08 diary-float
  • 6:48 Tip: Add links to task titles
  • 6:59 diary-float
  • 7:59 The difference between active timestamps and SCHEDULED
  • 10:06 Including other diary files
  • 11:26 cal-tex-cursor-week-iso, printing planner pages on index cards
  • 14:59 Holidays
  • 16:45 Making calendars for other people
  • 17:27 Keeping track of when things were done on the house
  • 18:49 My first customizations: backspace, buffers
  • 20:32 Windows and super key
  • 23:23 Org Mode class on Udemy, agenda custom commands
  • 25:00 toggling tags
  • 26:57 TODO states
  • 27:21 Functions for Org Agenda
  • 28:34 exeln, shellfn: executing things in DOS
  • 30:22 Middle mouse click
  • 31:59 Keybindings in other apps: Vivaldi
  • 34:09 M-s M-w, eww-search-words
  • 35:50 Saving links with org-store-link
  • 38:29 How I got into Emacs
  • 41:45 Maybe my own theme?
  • 42:26 Other editors? Always Emacs
  • 43:57 Package names
  • 45:54 What's next? Maybe auto maintenance
  • 48:31 Vibe-coding?
  • 50:53 Where people can find me
  • 52:02 Org Mode source blocks
  • 52:49 Slideshows?
  • 53:50 Emacs Chats?
  • 56:33 Other resources that would be nice to have

Transcript

Transcript

0:00 Opening

Sacha: I'll go live if that's okay with you. Yeah, good to go?

Raymond: Okay.

Sacha: All right, going live.

Raymond: Let me just stop sharing right now.

Sacha: Hi everyone, this is Emacs Chat. Emacs Chat 23. Today I'm here with Raymond Zeitler who has been using Emacs for a long time. Your EmacsWiki page says since 2000. And I know for sure that you've been commenting on my blog since about 2008, probably even earlier, I don't know. Everything gets lost in the mists of time. I would love to chat with you about the things that you've learned over the years, what you're still fiddling with, and the things in your configuration or workflow that aren't obvious to people who are reading configurations. It's just Emacs Lisp, but it doesn't show people what you do with Emacs that makes you stick with it over all this time.

0:57 Introduction

Sacha: So yes, but of course, we should do a bit of context setting. You have a lot of different hats. You're a historian, you're an electrical engineer. How would you describe yourself?

Raymond: Well, right now, I would say I'm an electrical engineer, but I spend most of my time, instead of designing stuff, I work on the workflow for the design. And I'm writing scripts, you know, to automate various parts of the design. Now, I just want to pause here because I hear like a 10-second delay.

Sacha: Yes. Oh, you have the video open in another tab. Yeah, so the 10-second delay is there in case we need to panic, you know, in case you accidentally flash something you'd rather keep private. But it can be quite disconcerting to hear yourself talking at the same time that you're trying to say something.

Raymond: Okay, I think I fixed that. Okay.

1:57 I love automating workflows

Raymond: Yes, so I'm an electrical engineer, but I also love to do scripting. Automating any kind of workflow is my favorite thing to do, and I would just love to go around and help people to find ways to automate the workflow. Basically, I was doing that ETL, you know, extract, transform, and load many years ago, I mean, dozens of years ago, and showing people how to do that too for them, and you know, when they look at me and they say, oh my god, thank you so much, I'm so glad... You know, it used to take me hours to do this. Automating a design flow is a good idea once you have all your script in place, that serves as your documentation. If there is a problem with the design, you can go back to the script and update it. So the next time, you're not going to have that problem, hopefully.

Sacha: You've been learning Python recently, too, right? I can imagine that helps a lot with automation. Are you taking advantage of things like Org Mode as well for the things that you can partially automate?

Raymond: Absolutely.

Sacha: Tell us about that.

Raymond: Oh, I figured that we should save for the last, because it could take the whole thing.

3:20 Org Mode switch

Raymond: But yes, I started using Org Mode after you jumped ship from Planner Mode. I know that you and John Wiegley were big on that, and I used to use Planner. And I delayed switching to Org Mode, but eventually I latched onto it really well. So one thing I used Org Mode for at home was for bill pay, you know, because you can schedule things recurring. So you got your mortgage, you can recur, you know, and the recurrence is well thought out. You know, you could have it scheduled exactly 30 days away or one month.

4:05 diary-float

Raymond: What I found recently, though, is you can use the diary: diary-float and diary-warning. Those functions can be used in Org Mode in place of the schedule. So that's really cool. I have a lot of meetings that occur, let's say, the second Wednesday of the month and stuff. There's really no way to easily do that out of the box with Org Mode. So that's fun to do. Let's see. I'm going to share my Org now, if you want.

Sacha: Sure, go ahead. If that's okay with you.

Raymond: Sure. Well, I deleted some of the stuff. You know, not all the files are there.

Sacha: Thank you. It's always interesting to see, because a lot of times, when we're trying to demonstrate Org to people, we're like, okay, here's a small example. But when you see it in the context of someone's actual life, with the tons of reminders they have... Your agenda is very full, for example. I'm not the only one with things that are scheduled for over 100 days.

Raymond: And actually, your talk isn't on here, so that's kind of strange. So, for example, I was talking about bills, right? I don't know if you can see that.

Sacha: Yeah, I can see that.

Raymond: It's not the same.

Sacha: Yeah, I see. And you're using the logbook. You can keep notes in a task. You can put all the things there.

Raymond: Yeah. So, you know, something like a mortgage or your utility, that's pretty standard. That's just +1m, you know, for the recurrence. Let's see. Yeah.

Sacha: Yeah. So basically, you have the regular or repeat things, plus one month or plus one week for the things that can be expressed that way. But you also use diary-float for the things that are second Wednesday of the month.

Raymond: Yes. So let me try a different Org file for that. Oh, everyone, I have to do this too.

Sacha: Oh yeah, you can set a global font default scale thingy. I don't remember exactly how to do that, but... [cut due to passwords] I'll move your screen off the thing first while you talk, and then I'll move it back when you're ready. So we had a bit of a "Oh no, he's showing me like meeting passwords online." So if you saw that, which probably you didn't because 10 second delay, just ignore it. And then we'll go back and scrub things later. Let me know when it's safe to look again.

Raymond: Okay, here we go. So here's a meeting.

Sacha: Okay, okay. We got this. We got this.

6:48 Tip: Add links to task titles

Sacha: I also want to point out, I love how you're using links in the task title. You know, that did not occur to me to have the links right there so it's easy to get to from just the overview.

6:59 diary-float

Raymond: [cut due to passwords] ...which works really in a diary file.

Sacha: All right. Let me move it back so people can see.

Raymond: It works. This is great because it works in Org Mode too. If anyone doesn't know it, this is the month. And true just means that this meeting occurs every month. And I believe this means Monday.

Sacha: No, Tuesday. Although... Your comment says Tuesday, yeah.

Raymond: Yeah, Tuesday. So that's the second day of the week, with Sunday being zero. And then this is the week number, the second week. Second Tuesday of every month. And then you could just put the time there as well.

Sacha: Yeah, yeah. I have actually personally never used this syntax, but I see people use it for things like Emacs meetups and they're like, okay, yeah, we meet every second Wednesday or whatever, but here's the thing that you can just put into your Org agenda and it'll work.

7:59 The difference between active timestamps and SCHEDULED

Raymond: But the problem with this, though, is that it doesn't obey the, you know, if you mark it done, it'll be marked done. So it won't show up again. So I'm actually starting to put these in my actual diary because you know, I don't really need to mark the meeting done.

Sacha: You know, you can take out, just remove the scheduled keyword. You can have the active timestamp and it will show up on your calendar, but it doesn't have to be marked as done. And it'll just keep showing up whenever you need to. So this is the distinction between scheduled, which is actually not like a scheduled appointment, it's like a task that you're scheduling for a specific day, versus just using an active timestamp, which is the stuff within the angle brackets. It can be anywhere in your entry. It doesn't have to be the second line after your heading. Then it will show up in your agenda, but it's not going to keep showing up like the next day. It's not going to say it's overdue. It's just going to be for that day.

Raymond: Okay. Yeah. There was somebody who tried to solve the problem, though. And they came up with next-spec-day, a function, but it's not possible to compile that with the modern Emacs. So I'm just happy with the way I have it now, though. Yeah. But when I first started using Emacs, the diary and the calendar were one of the first non-text editing uses that I had for it. And I'm really getting back into diary. I hope I don't show anything else.

Sacha: Tell you what, I'm going to move your window away. Okay. And then you can do your thing and then I can move it back when you're comfy.

Raymond: Okay.

Sacha: Yeah, I know how to do this now. This is good. I have two monitors so I can control.

Raymond: Where's my screen? Oh boy. So what I'm showing here

Sacha: I put it back so people can see.

10:06 Including other diary files

image from video 00:10:09.867Raymond: My main diary is just diary. What I'm doing is I'm using includes, because I like to break it up into various files that I can comment them out if I don't want something so busy. The reason I'm doing that is because I was tooling around in calendar in the calendar functions and there's actually cal-tex-cursor functions that so when you go into calendar, for example... That's also small, right?

Sacha: It's okay. Everyone has seen calendar. Well, most people have seen calendar at this point, so we know what the calendar is. Okay. What are we showing? What are we seeing?

Raymond: So if I wanted to, let's say for next week, what I could do is create a, let's see, cursor... I forgot the command.

Sacha: I'm surprised you don't have completion set up.

Raymond: Yes.

11:26 cal-tex-cursor-week-iso, printing planner pages on index cards

image from video 00:14:04.867Raymond: Okay, so this is what I like to do. So this function, cal-tex-cursor-week-iso

Sacha: It's okay. It's the curse of the live demo.

Raymond: All right, I'll create mine.

Sacha: Change cursor shape, huh...

Raymond: All right, so for some reason that's not working. But what you end up doing is you can create a weekly planner, kind of like a page in a date book, and it will show everything from your diary if you want...

Sacha: In a nice printed format or like a nice visual format.

Raymond: Yeah, I have to... How do I get that? I don't know why it's not working here. So...

Sacha: Certainly the layouts of things, the layouts of date planners is something that I sometimes envy about my paper planner days. Like you could see things. I also wanted to point out something that I hadn't considered. You were using diary for diary entries, it looks like also not just appointments and reminders, but also this is what happened that day. Ooh, that is pretty. Do you actually print these out or like read them on an e-reader or just look at them?

Raymond: I did. Yeah, I found out that my printer can print double-sided on index cards.

Sacha: Oh yeah, double-sided.

Raymond: So I actually created my own little book here. So what's nice about this is, you know, when you go into a store to look for some planner, many of them, like half of them, don't even have the lunar phases. And let's see if this has a lunar phase.

Sacha: So printing planner pages on index cards. Very cool.

Raymond: So you've got your full moon there. And because I was very active in photography, nature photography in particular, and doing landscapes and stuff. So it's really helpful to know when the full moon is, more so sunrise and sunset, which I have here. Because you get, especially in the winter, you get great shots at around sunset. Yeah, so that was something that I was really interested in.

Sacha: Oh, it's so cool. It's something I'd never considered using Emacs to generate your custom, you know, calendar planner thing that you then take offline because you're out there in the field. You're taking pictures. You don't want to open your laptop or look at your phone or whatever. It's just your index card. Nice.

Raymond: And there's some astrology in there.

Sacha: [cut due to password] We're back to streaming. Yeah, birthdays. Gotcha.

Raymond: Birthdays. And then, so I'll just... I wonder if I could do this safely.

Sacha: Give me a heads up, I'll move the screen off and then I can move it back when you give me the heads up again.

Raymond: I'm pretty sure my .emacs is pretty... If anyone wants to see this and download it, it's on emacswiki.org. Just look for the page RaymondZeitler.

Sacha: Yeah, it's in the related links now for the blog post. Gotcha.

14:59 Holidays

image from video 00:15:07.533Raymond: So what I was looking for here is my list of holidays. So what you could do with... This is basically a calendar thing, but you can set up all your holidays. For example, Towel Day is coming up. It will be Monday for you Hitchhiker's Guide geeks. You've got your Star Wars Day, you've got Pi Day, which you won't find on a regular calendar, of course. And that's an atrocious thing here.

Sacha: I was just admiring that. It's a very complicated expression, but you can do it.

Raymond: You can, right. So that's what I came up for Election Day. And if anyone's a Seinfeld fan, you've got your Festivus. So that's a neat thing. Yeah, and don't worry about the longitude-latitude. Everyone knows where I am.

Sacha: [another password hiccup] ... dealing with the panic, it's good. It's good practice. And also everyone is very nice, so afterwards, I'll just probably make this unlisted and then see if there's anything that actually needs scrubbing. But probably it's all good. Yes, so you've got calendar, you've got holidays, you print them out. Are there other ways that you use Emacs, kind of in this online-offline way? Are there any other things that you like to print out, or do you do the rest of the things in your computer?

Raymond: It's all on computer, yeah. So the only thing that's printed out is the planner datebook. By planner, I mean this thing. Okay. So...

16:45 Making calendars for other people

Raymond: Oh, yeah. Anyway, getting back to why I break up my diary into multiple files is eventually I may want to create these things for other people, right? Print out a date book for my wife, for example. So she's going to want to know when Towel Day is, right? Well, that's a different thing, but she's not going to want a lot of other things.

Sacha: Yeah, it's very customizable. You can just say, okay, include these, you know, modules in the calendar. Yeah. Yeah. Yeah. Cool.

Raymond: So, and then getting back to the diary again, yes.

Sacha: I can move this. We're safe. Yeah. We're safe.

Raymond: Okay.

17:27 Keeping track of when things were done on the house

Raymond: So one thing I like to do is keep track of when things were done on the house.

Sacha: You've got a license plate?

Raymond: No, there's really nothing bad here. For example, if you want to know when you have to register your car, you can put that in there and it'll show up on your little planner. So I thought that was pretty neat.

Sacha: And I like that you can say a number of years ago, so it automatically keeps track of that. You can wish somebody a specific number of years, happy birthday, instead of just a generic happy birthday. You don't have to do math. Nice, nice. Diary, I think it's underutilized.

Raymond: It is, yeah. And what I like about Emacs is that the people who are, you know, creating functions and adding to it use it and have really good design ideas. So, oh, this is, let's go back to something else here. Okay, so back to my .Emacs. Let's see. Let me just... In the interim, before we come up with something else to talk about, I'll just talk about some of the modifications.

18:49 My first customizations: backspace, buffers

Raymond: And by the way, when I first started using Emacs, I decided not to do anything. I'm a Windows user, so naturally you might want to use CUA mode, but I never did that. And the first customization I did was... For some reason the backspace key was doing the delete function. I think that was Emacs 19. So that was the one thing I changed. And then the other thing I changed is very soon I had multiple buffers. Like if you're using Emacs for any amount of time, even like 10 minutes, you'll have multiple buffers. And I was using a tabbed web browser at the time, so it's easy. To switch tabs by just pressing the Ctrl-Tab key or Shift-Ctrl-Tab key to switch between tabs. And I figured, let me do that with the buffers. And so that's somewhere in here.

Sacha: Oh yeah, there's a control tab, control shift tab, next buffer, and previous buffer.

Raymond: Yeah, so that was one of the first things besides the delete key modification that I did. But I'm also now, since I have multiple windows open as well, I'm using the windows... Next and Windows Prior. Next is, I think, the page down key, I believe. And Prior is the page up key.

20:33 Windows and super key

image from video 00:21:50.033Raymond: And how you can get to use the Windows key is, I got that from Xah Lee's website. And where is that now?

Sacha: Yeah, you make it the super key. I use Xmodmap but other people can use different things depending on their setup. Although lately I've been experimenting with using Kanata so that my modifiers are one-shot modifiers. I can tap the super key and then I can let go of it and then I can press whatever key is next so I don't have to hold them at the same time. Oh hey look at that it's actually an option! I didn't even know that it was. You can change it right from Emacs. Nice.

Raymond: Yeah, so this is what I set up. I lifted this from the website. There's the URL. And if you're curious, you can go to that Emacs wiki website and see this. The only thing that I wasn't able to get this to work until I added this statement, which I found in Stack Overflow or something like that.

Sacha: That is interesting. Yeah. All right. So does it mean that Emacs is entirely responsible for the Windows key? You don't do anything else with it outside Emacs?

Raymond: Right. So yes, it intercepts the Windows key before Windows does somehow magically, which can be kind of frustrating because sometimes I do want to open the start menu from within Emacs and I'm pressing it and saying, why isn't this working?

Sacha: This is where you just get used to having your own launchers within Emacs.

Raymond: Yeah, yeah. Well, you know that you're a good Emacs user if you start using the Emacs key bindings in other programs. You know, how many times I've used C-y to paste something in, you know, my web browser. Oh, boy.

Sacha: Yeah, it's not the C-y that gets me. It's the C-w because that closes your browser down.

Raymond: Yeah, oh yes, that can be dangerous. But actually C-y can be bad too, because it's like the redo function in a lot of programs. So if you've undone something, and then you redo it, you can get very confused very quickly. Anyway, so this is a neat thing to do. Some people might want to try that.

Sacha: Yeah, for sure. Having a super key means you can then go on and do other things with it. You can have all these key bindings because nothing binds to the super key. So you can have all the single character key bindings you like.

Raymond: Exactly, yeah.

23:23 Org Mode class on Udemy, agenda custom commands

Raymond: So I was taking, believe it or not, there's an Org Mode class on Udemy. And it's... Rainer König did it. I don't know if I pronounced his name right. But he inspired me to do custom commands. So for example, if I want to look at all my bills for the week, I would just press the b w.

Sacha: Do you want me to move the window?

Raymond: I don't know. Is there anything dangerous here? I'm not going to do it, but I'm just trying to point out my thing.

Sacha: Yeah, yeah, yeah. Different agendas for slicing and dicing your Org data in different ways.

Raymond: Yeah, yeah. Remember you pointed out earlier that my agenda was jam-packed with stuff. The way I manage that is I came up with a way to easily apply the today tag to all those things. And I came up with some functions somewhere which I bind to C-M-S-t. Let's see if I can find it.

Sacha: That is interesting. So you're using a tag for the things you want to do today.

Raymond: Yes.

Sacha: Versus scheduling them, because if you schedule them for today, then they will still show up tomorrow.

Raymond: Well, yes, that's true.

24:53 Toggling tags

image from video 00:25:00.400Raymond: So yes, so these are the two functions I came up with. Oh, you're toggling. What's that?

Sacha: You toggle that. You have something that lets you add or remove a tag.

Raymond: Yes, yes. Yes, exactly. And maybe I could demonstrate that without displaying too much stuff here. Okay, so here, so in the agenda, I'm a little bit worried about updating. See, okay, so I don't know if you can see it, but I just invoked it and then down here in a little.

Sacha: Oh, yeah.

Raymond: It says you have to press s r to save and refresh the screen. And the reason why I didn't automatically refresh and save files is because I think that's a dangerous thing.

Sacha: Yeah, because you've been removing things. Okay, okay. But the idea there is you can turn the tag on and off from your agenda directly, which is interesting. Yeah, it's there. And you have a different view that shows you just the stuff you're focusing on for today.

Raymond: And I have that bound to "C-c a .". This is going to be small. So there on the top are my things for today.

Sacha: Yeah, so different ways of prioritizing. So your agenda is the stuff that you want to keep on your radar. And the today stuff is the stuff like, okay, you got some time. This is what you're actually going to work on.

Raymond: Right, so.

Sacha: Yeah, there are different ways to approach it. Some people have a much more minimalist, okay, if it's on the agenda, it's because I want to do it that day. And then they have a different view showing them the stuff that they want to keep on their radar. But the nice thing about Org Mode is that it accommodates all these different ways of working.

Raymond: Yeah.

26:56 TODO states

Raymond: And getting back to the Rainer's class on Org Mode, you know, it's not like the way Carsten Dominik set it up with the default tags of to-dos. What is it? To do, started, waiting. He does something a little bit different, but it works for him. So I think that's kind of cool too.

27:21 Functions for Org Agenda

image from video 00:28:06.200Raymond: And by the way, you need two functions. You need one that works in an Org file and another one in the agenda because they don't work the same way.

Sacha: I have some functions that act that way, and I usually end up checking if the major mode is derived from the Org agenda. And then there's an with Org agenda. There's a macro that lets you run the code in the context of the task. So if you needed to kind of switch those together, it's possible. But you already have something that works, so it's fine.

Raymond: Yeah, and it's easy because, you know, I copied this from some existing function like, you know, when you press Z, for example, it creates a note. So you can leverage that code and write your own code instead.

Sacha: It's called org-agenda-with-point-at-orig-entry. It does the thing. You know, this part that you're doing at the moment with manually finding the marker and jumping to it and all that stuff. In the future, if you find yourself writing one of these agenda functions.

Raymond: Yeah.

28:34 exeln, shellfn: executing things in DOS

image from video 00:29:15.767Raymond: So what else do I have here? Oh, so sometimes I just like to execute. So I do a lot of batch files or scripts, and I'll just do C-c x to send that particular line to the DOS prompt just to execute it.

Sacha: Oh, execute line. Okay, so that's what EXELN means. That's cool. So it's basically you can evaluate things without having to switch and paste and switch and paste and all that stuff.

Raymond: Yes. And just to demonstrate, if I wanted to do the dir command.

Sacha: It's like an eval-last-sexp, but for DOS. Yeah, so this is... And hats off to you for, like, batch scripting with DOS. I'm very spoiled with my bash and zsh, but you're in Windows and you're making it work.

Raymond: Yeah. Which is like a handicap, isn't it? And then I can just send the whole buffer to the command prompt, which I think now there's a function that don't really does that, you know, out of the box. Maybe not. And then if I wanted to insert the date, you know, just some easy stuff like that.

Sacha: Yeah. Yeah. Yeah. I recently added this insert date and time thing as an abbrev, So I just type it and that frees up more of my key bindings for other things. Yeah. But it's surprising. You always find yourself wanting to refer to the time and that way you don't have to look.

30:27 Middle mouse click

Raymond: I don't remember how Emacs treated the scroll wheel or the middle mouse button, but I found that this was very useful. I believe what you can do is click the mouse. Let's see what happens. It pasted what I had there.

Sacha: Yeah, yeah. I think middle is usually paste, but it sounds like you've got it. Oh, okay. So, so you, you can scroll if you're dragging, but you can also click, just middle click to paste. Yes.

Raymond: Yeah. So it's fun. There are some things that down-mouse-2 does, and I'm not able to do that now. I think, for example, spell checking, if you want to correct a word at point, I think the command is to do the mouse-2 button, but I no longer can do that. But that's okay.

Sacha: Over 20 plus years of Emacs, I'm sure parts of your workflow have come in and out of viability as things change. I feel like Emacs does make more of an effort to keep things pretty stable for the most part, hence all the contortions that new Emacs development has to do in order to keep things working but also adapt to the times.

31:59 Keybindings in other apps: Vivaldi

Raymond: I think I mentioned before how I co-opted the ability to switch tabs. I got the idea from the web browser and incorporated it into Emacs. But I've started to do the opposite. So if you do C-k, which deletes anything from point to the end of the line...

Sacha: Yeah, you've up-cased a bunch of things.

Raymond: Yes, I am going to have to close this because I'm really scared now.

Sacha: revert-buffer, maybe? Or undo?

Raymond: Yes, I'm trying to do undo. That's what I meant to do. We're back. There we go. So, yeah, because I did C-x C-u instead of... whatever. So what I've decided to do then is if you're using a web browser and you're opening new tabs, which I do, so I am able to bind a key and I'm using control shift K to close all the tabs to the right of the current tab. So that's sort of like borrowing an Emacs keystroke and using it in my browser. [Sacha] How are you doing that? Are you using AutoHotkey or does Vivaldi let you do that automatically? Yes, it's Vivaldi. So if I go into the Settings - Keyboard shortcuts... So actually, I don't know how to increase the size of this.

Sacha: That's fine. We can see it. People can go open up Vivaldi if they're curious. But the idea there is you get used to these conveniences or these ideas from Emacs. And now you're like, OK, I want to make my other apps feel at least a little bit this way.

Raymond: Yeah. Yeah, so.

Sacha: Yeah?

Raymond: And I still keep learning stuff about Emacs.

34:10 M-s M-w, eww-search-words

Raymond: Believe it or not, I didn't know that you could select a region and then do an internet search on it, right?

Sacha: Today I am learning. How do you select a region and do an internet search on it?

Raymond: So M-s M-w (Alt s and Alt w) is loading in EWW. And this is what Atomic Chrome Start Server is. And that's actually a Chrome extension that you can... Okay, so if I go to some... Okay, okay.

Sacha: It is EWW Search Words. Okay, good. Cool.

Raymond: So if I go to your website now and I want to type a comment, which I think I can do, right?

Sacha: Oh, I switched to just doing comments through email. Because Disqus was getting all ads-y and annoying and tracking JavaScript and stuff. So now it's like every post has an email me if you have thoughts. Sometimes it has a Mastodon link if I've remembered to post it to Mastodon beforehand.

Raymond: So... What I'm trying to do is find a window that I can type into.

Sacha: There's a search box up there to the top. But basically, you're going to show us how you can take stuff from the browser and put it into Emacs for easier editing.

Raymond: Yes.

Sacha: All right.

35:50 Saving links with Org-store-link

Sacha: Charlie has a question. So Charlie asks, do you use Org Mode protocol at all for browser to Emacs interaction? If so, were there any complications to set it up on Windows?

Raymond: I don't.

Sacha: Is there like bookmarklets for capturing or doing things?

Raymond: Yeah. So, oh yeah. So capture is just a wonderful tool. Okay. So I'm not sure I'm I can answer the question, but what I would say is, let's say if I wanted to... Alright, let's try this. This might not be too bad. So let's say I wanted to create a link to some ad. So no, I don't use EWW to capture the link. But I just learned out how you can do it. But if I wanted to go to another, all right, well, this is a silly example. But if I were to do just a help, Let's say, if I just wanted to find a place in the info, in info, if I do C-c-L, it'll create a link for me, and then if I wanted to here, put that link. So it's already there in the mode line. Yeah. And then I can say info. And I can have that there. So this will go, and I'll close this help.

Sacha: Okay.

Raymond: And then if I click this, it'll open back up.

Sacha: So you use the org-store-link a lot. Do you use org-capture as well?

Raymond: Yes.

Sacha: I saw your keyboard, your key binding for it. But you don't necessarily have bookmarks or extensions in Vivaldi to do the capturing with the context from your browser. You'll just copy and paste the link manually.

Raymond: Exactly. That sounds like fun, though. [Sacha] That's a nice thing about Emacs. There's always one more thing to tweak, one more thing to learn. You've been tweaking your Emacs for a long time, and yet there's still more to do, to fiddle with and explore.

38:24 How I got into Emacs

Raymond: Yeah if you can think way, way, way, back, how did you get into Emacs in the first place? Oh, okay. So, you know, I was thinking about how my career, like the first half of my career, I've been using an IBM PC and MS-DOS, and it was all command line based. And as well, those machines were quite slow. So what we would often do is Write batch files and basically have things happen while we were away. Go and get a cup of coffee or leave for the day and come back the next day and hope it was done. I was working with text files for 20 years. I had a really good text editor. It was called Brief. And it had a lot of nice features. It was, of course... You could record and playback keystroke macros, right? Sounds familiar. It also had a scripting language. Of course, it had undo. But the nice thing I really liked about it is that you could do column editing, right? So you could delete columns of text, or add columns, or cut and paste and move them around, and stuff like that. Because if you're using a lot of csv files, it's really columnar in nature. I guess I can't pronounce that word. But when I moved to Windows, that text editor didn't work so well. It wasn't very happy in a multitasking environment And so I started looking around for stuff. I did find an editor actually that it had the same key bindings as brief, but it had one problem. And if you open, for example, if you opened a binary file, that had a null character, it would crash. So I don't know if that bothered me. So then I started looking around for another one. And then I guess it was in Usenet that somebody said, why don't you try Emacs? As if I heard of it and decided not to. So I did, and I really liked it. So maybe I'm going to go back and search for that conversation and thank the person. That'd be something I could put on my Org agenda.

41:05 Did it click for you right away or is it something that grew on you over time?

Sacha: Did it click for you right away or is it something that grew on you over time? I started right away with the tutorial And I said, ah, this is crazy to have to do. And I don't even know how to navigate with the original key bindings. So I expected to be able to use the arrow keys. And I don't think it was set up that way. But then I stuck with it. And like I said, I didn't adopt the CUA binding or anything like that. Yeah, and I just grew to learn it.

41:45 Maybe my own theme?

Sacha: I had thought about coming up with a theme for it, a different color theme. And I tried that for a while, but then when I would use a different mode, it just looked terrible. So I'm keeping the same mode now. What I hear more and more people are doing is they'll take something like modus themes and then they can change the colors of it without necessarily having to make all the mappings of, okay, this thing in this mode, you should use this kind of face. So if you still want to have your customized colors, that might be an approach to consider.

Raymond: Yeah. Going to stop sharing for a second.

Sacha: Sure.

42:26 Other editors? Always Emacs

Sacha: Did you ever flirt with other editors again after getting into Emacs? Or has it basically been mostly Emacs for the last while?

Raymond: Oh my gosh, how could you even say such a thing? No, it never occurred to me to do that. But some of the guys were using Notepad++, which, you know, mine is the only computer with Emacs. But if I go to another computer, they have No pad++. I would be using that. And it's nice. It has a tabbed interface so you can switch between files very easily. But I've never considered switching to something else. And even, you know, I took a vibe coding class. So they have you use VS code or anti-gravity or something like that. And I'm thinking, wouldn't it be nice if I could You know, switch to my Emacs editor and do the typing there and then switch back to anti-gravity. I don't know. But I hear some people are vibe coding with Emacs, so I might look into that.

Sacha: Yeah, there's been an explosion of different ways that people are interacting with these systems. And of course, people are also totally welcome to keep using Emacs without it. But if people are curious, as the usual Emacs way of doing things, there are more than a handful of packages all with their different workflows. You'll find something that fits.

Raymond: Yeah.

43:57 Package names

Raymond: I wanted to ask you, speaking about EWW, do people pronounce that ew? The thing about a lot of these packages, they have these wonderfully self-effacing names. There's one called Dismal. That's the acronym for it. And it's Dismode Ain't Lotus. It's basically a spreadsheet. So I was just curious about that.

Sacha: I think we spend so much of our time reading rather than you know hearing or talking to people so then it's only in the middle of a conversation of a very rare conversation one can have about Emacs either on stream or in person when you're like okay is it Magit or magic you know do I say ew but that that seems so rude ew ew ew the Emacs web thing yeah sure

Raymond: And that's pretty new, isn't it? That mode? Because I remember doing W3 and then WW3.

Sacha: There was a w3m and elinks. I remember that too.

Raymond: Links, I had a version of that on my, you know, like a DOS version of it, believe it or not. But it was very utilitarian, you know.

Sacha: Yeah, yeah. Sometimes you just want to browse the web or get the information without all the clutter that goes on and, you know, just like all the layouts and the cookie pop ups and whatever. Just get me the stuff. Yeah. Yeah.

Raymond: Well, I do think I'm going to be incorporating EWW more as I think it was Charles who said, you know, creating a link using C-c l to create that link and it basically copies what's around it. I do see the usefulness of that.

45:54 What's next? Maybe auto maintenance

Sacha: Yeah, yeah, because org-capture and 00:45:57.936 -> 00:46:00.339 org-store-link can just pick up the context for you and then it's so easy to go back to things afterwards. I've also heard good things about org-remark. So that's something that's on my to-do list as well. There are always all these things to be curious about and learn. What are you looking forward to exploring? So there's EWW. What's next for you in this Emacs journey?

Raymond: Oh boy. I was thinking of using Org as a car maintenance tool. And as you know, Org is great for scheduling and projecting out things. The thing about auto maintenance, though, is a lot of times something has to be done at a certain mileage. Like every 5,000 miles, you have to rotate the tires, for example. If you're driving regularly, like maybe 100 miles a week, you could say, oh, that's going to happen in a year. But if you're driving as erratic, then you'll probably want a way to download your mileage from the car. Cars are basically just computers, aren't they? I mean, they're computers that we drive around, or sometimes they drive us around, frighteningly so. I'm sure someone is thinking about or has already come up with a link between a desktop computer and a car. Okay, I'm not seeing. Well, maybe. Maybe that's giving somebody an idea there. But maybe Lori Wired or something can come up with that.

Sacha: And even, you know, even a manually scheduled reminder, hey, you know, just write down what your odometer says, and then some kind of logic that takes a look at that reading and says, okay, it's past this threshold, schedule this task. And have that done semi-automatically. Sounds really interesting. Because then you could have all sorts of things to say, all right, I have this manually scheduled recurring task to manually log something. But then it kicks off these processes that then surface all these other tasks that I should do. Could be fun. How would you do that? That sounds really cool.

Raymond: So I don't know if I'll ever do that because I'm pretty lax with my car maintenance anyway.

Sacha: It could be like every six months check to see whether, you know, it's time.

Raymond: Yeah, yeah.

48:31 Vibe-coding?

Raymond: But I probably would try the vibe coding with Emacs eventually. You know, every so often I see it on Reddit or Stack Overflow. You know, somebody is trying this package or that package. Yeah, it might be worth trying.

Sacha: What are the challenges that people sometimes find when it comes to vibe-coded stuff? It's great for the initial prototype, but once you start digging into it, it's hard to modify it yourself, so then you become dependent on it. And then, of course, the large language model can't quite get some things. How are you finding this so far? I mean, this is very early in your journey. I think you're still experimenting with it. But do you find that it's working out for you? How is it with Emacs?

Raymond: It was just like you said, like it just can't get it. Like I told it, well, fix this because I don't like that format, and then it will do it differently. And then, no, but it changed something else that it was doing correctly, and I just couldn't get it to work. And the other thing is, so the course that I was taking, they wanted... Next.js And I just can't describe it. So I was trying to back up my computer one day after installing it, and it's doing on and on in like 20 minutes. Just because there's so many files and it's just crazy. So I thought it was fun to try it, but I think I'll just stick with what I know best.

Sacha: In a way, I'm delighted. We've come full circle. Emacs is now the lightweight solution. It is a lot of fun. Emacs, less AI. AI is not quite at the fun point yet, I think. But I'm glad that there's still more to tinker with and explore. I have about eight minutes before the kiddo runs out and starts lunch break.

50:52 Where people can find me

Sacha: I'm guessing if people want to keep up with your adventures they can check your EmacsWiki page for updates. You have some code shared on Codeberg and you mentioned your LinkedIn profile which is in my thing, but how can people keep up with what you're learning?

Raymond: I'm surprised that people would want to.

Sacha: I want to. I do not have an auto to maintain, but I have a cargo bike that I've got to keep up with also. So I'm very interested in these mileage-based task reminders, if you work something out.

Raymond: Yeah, I'm not pretty good about publishing stuff. I don't know. That's a good question. I'll come up with something. Maybe I'll be more diligent pushing my updates to the Lisp Codeberg repository. I don't know.

Sacha: Sometimes it just takes somebody saying, your stuff is interesting. I'm telling you, your stuff is interesting.

Raymond: Okay. Thank you so much.

52:02 Org Mode source blocks

Raymond: By the way, I am using source code blocks now. So like we talked earlier about executing the batch file, I can now put a little batch file inside a source code and execute it that way.

Sacha: You have those links in your heading and in your Org task bodies. I've been enjoying using Elisp and Shell link types so that I can put in those partially automatable things. In my workflows, because sometimes you're like, I do have to do it manually. I just can't write a function to do everything. But at least they can document it step by step and say, okay, do this, run this code block, you know, just do all that stuff.

52:49 Slideshows?

Raymond: And the other thing I'd like to try to do is I know some people can create slideshows with Emacs. And so that looks like it would be worth pursuing. I'd like to try that.

Sacha: Oh, yeah. Are you thinking of it for the history stuff that you're involved with or other things that you're teaching?

Raymond: So I'm starting to present my photography as a slideshow. And I thought I would try that. And now I see that Emacs can support images. I don't know how it would work as an export, but I look into that now.

Sacha: Yeah. And even, you know, the couple of times that I've wanted to use Emacs to create, you know, even just a PDF of these pictures, just being able to automate that instead of pasting and resizing, it's like, ugh, don't do that that way, just have the computer do it for you, and Emacs is great for it.

53:50 Emacs Chats?

Sacha: I've been meaning to ask you, what is your viewership with these Emacs chats?

Raymond: Are you starting to see a lot of traction with that?

Sacha: I have no idea. My goal here is just to get stuff out of interesting people's heads. Interesting stuff out of, yes, interesting people's heads. And I think mainly I'm using it as a way to keep improving my transcription workflow. I guess I like to train everything into text afterwards. That way it's searchable. But it's been really fun getting a sense of how people are using it because we all have such different workflows. And as I was saying in the beginning, you don't see that when you're looking at someone's config. You're like, okay, I see that the code that sets the key bindings, but how does it work together? And then seeing your Org file, I'm like, Oh yeah, why am I not putting the links right there so that I can just get to them from the agenda? Diary can do that? All that stuff is really, really interesting. It's been great revisiting it after such a long break, taking care of the kiddo. Now the kiddo is slightly more independent and even has moments where she's like, bye mom, I don't need any help. Like, okay, yes, I'm just going to do my Emacs thing.

Raymond: Asking for the car keys yet or not?

Sacha: No, no, no. Also no car, but someday she's going to, you know, and she actually already likes to bike to the park on her own. So she's 10. She's not at the car level yet, but definitely in the biking and walking by herself, she's keen on that. Gradually, independence for both of us and the ability to explore things. I'm really liking these Emacs chats. With you and Shay Arison, who's also been a long-time reader, it's like this continuation of a conversation we've been having over decades now. I can't wait to see where this goes next. I've picked up a lot that I, again, would not have really understood just by looking at your EmacsWiki page and I hope that other people watching can also get a sense of, like, this is what it looks like in use. Sometimes people think oh, I need to make a video that's going to be a snazzy demonstration of this really technical setup, but sometimes it's just the little things that make your life better.

Raymond: Well, I really want to thank you for doing this, not just this Emacs chat, but just having your web page and organizing all the Emacs information. It's just been a wonderful resource.

Sacha: Thank you. In the last two minutes I have before I get like, "mom!",

56:39 Other resources that would be nice to have

Sacha: what kind of resources would you like to see going forward? What would make your learning even better?

Raymond: Well, you know, it's just, you know, just saying something that you did... For example, when you were... So when I visited your site and you showed how you could show the time in someone's native time zone, right? Which is a wonderful thing, right? But I had my own time thing that I was wondering. Like, I wanted to know if someone had a date, like May 21, what day of the week is that? I know that I can't go on a meeting on Tuesday. I'm trippable. So I figured out a way you could select it and send it to a custom search engine that searches on DuckDuckGo AI and says, what day of the week is this? And just include the date. And it tells you.

Sacha: Yeah, yeah. It's nice to be able to modify things, not just in Emacs, but in browsers or anything else. And my personal approach for that date thing would be like, okay, I'm just going to do an insert date, like a C-c C-! in Org. Because if I type in, you know, the part of the date that will get it to show up, it will include the day of the week. But that only works in Emacs, of course. Everything should be in Emacs. So yeah, I guess one of these little workflows, oh, I just figured out something, sort of posts can ripple out into other people imagining other things that they can do. And on that note, I'm going to wrap this up very nicely. I will try to mark this as unlisted so I can see if I accidentally let any of your passwords slip past my 10-second panic window. You're okay with your coordinates. That's okay. Yeah. All right. Thank you so much, Ray.

Raymond: Oh, thank you.

Sacha: And I look forward to more conversations.

Raymond: Yeah.

Sacha: All right. Bye.

Raymond: Bye bye.

Chat

  • sachactube: ​​This is for https://sachachua.com/blog/2026/05/em
  • charliemcmackin4859: ​:D
  • charliemcmackin4859: ​do you use org-mode protocol at all for browser -> emacs interaction? If so, was there any complication to set it up on windows?
  • charliemcmackin4859: ​I did slideshows a few times at a previous job with org-reveal. I liked it decently.
  • mtendethecreator: ​Hello sacha
  • phyzixlab: ​​Thank you both. Great interview
View Org source for this post

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

-1:-- Emacs Chat 23: Emacs Chat with Raymond Zeitler (Post Sacha Chua)--L0--C0--2026-05-21T14:30:32.000Z

Protesilaos: Emacs: ef-arcadia and ef-atlantis are part of the ef-themes

I have added two new themes to the current development target of my ef-themes package. Screenshots are available below. Remember that the themes are highly customisable: you can change practically everything about them.

  • ef-arcadia is a light theme with a verdant, humid aesthetic.
  • ef-atlantis is a dark theme with an aquatic feel.

Both deliver the familiar colourfulness and good legibility of the ef-themes.

Always click to enlarge the image for best results.

ef-arcadia

ef-arcadia theme sample

ef-arcadia theme git sample

ef-arcadia theme mail sample

ef-arcadia theme org sample

ef-atlantis

ef-atlantis theme sample

ef-atlantis theme git sample

ef-atlantis theme mail sample

ef-atlantis theme org sample

Coming in version 2.2.0 (next stable release)

The character of each theme is well defined. I may still make some refinements.

Remember that since version 2.0.0, the ef-themes are built on top of my modus-themes. This means that they are highly customisable, support a wide range of packages and face groups, and are extensively tested down to the finest details.

Enjoy!


The ef-themes are a collection of light and dark themes for GNU Emacs that provide colourful (“pretty”) yet legible options for users who want something with a bit more flair than the modus-themes (also designed by me).

-1:-- Emacs: ef-arcadia and ef-atlantis are part of the ef-themes (Post Protesilaos)--L0--C0--2026-05-21T00:00:00.000Z

May i recommend using your thumbs

This is my entry to the may 2026 emacs blog carnival hosted by Sacha Chua.

It is common knowledge that the default emacs keybindings can be a bit of a strain on the old hands. A common suggestion is to remap the caps lock key to act as control, and i did that for a while, but i don't think it's the perfect solution that is often suggested: stretching the pinky finger sideways and holding it down still results in pain after a while for me. Luckily i have the perfect solution with zero drawbacks: use your thumbs!

The first time i tried this was about five years ago. I put control on the key directly to the left of the space bar, and alt on the key directly to the right of the space bar. The thumb is very good at moving in this sideways motion, and i could immediately feel how much more comfortable my hands were with this layout. The trouble with this, though, is some keybindings using the thumb and fingers from a single hand still feel a little bit clumsy. Although the control and alt keys are in nicer positions, they still aren't perfect for all keybindings.

So i did the only sensible thing: i made the keys directly next to both edges of the space bar control, and the ones one key out alt. With this setup, i can use the left thumb for control or alt bindings using keys on the right side of the keyboard, and the right thumb for control or alt bindings on the left side.

Emacs is heavily based around keyboard shortcuts, so the benefits are immediately apparent. But as anyone who's ever used a mac will tell you, the command key is much more comfortable to use with all sorts of shortcuts than the control key is on windows or linux systems. You don't have to perform any sort of hand contortions, because your thumbs are almost already sitting on the modifier keys.

As i say, i've been doing this for about five years now, and i've never felt more comfortable typing. Setting this up is one of the first things i do when i reinstall my operating system, usually straight after i try to use a keyboard shortcut and realise it doesn't work because the modifier keys are in the original positions.

So if you're planning on trying out evil or something in order to make using emacs more comfortable, why not first try moving the modifiers around to see if those hench old thumbs or yours could alleviate some of the pain?

-1:-- May i recommend using your thumbs (Post)--L0--C0--2026-05-21T00:00:00.000Z

Irreal: EWW As A Way To Evade Paywalls

In my post on Omar Antolín Camarena’s May Emacs Carnival contribution explaining his reasons for using EWW as his default browser, I mentioned that Camarena said that one of the benefits of EWW not supporting JavaScript is that JavaScript is mostly used to make the user’s experience worse by doing things like loading ads, reconfiguring the user’s display parameters, and implementing paywalls.

If you had asked me, I would have said that any site using a paywall would also require JavaScript to load the content and, indeed, that’s true for some sites such as The New York Times but, as I discovered, it’s not true for a surprising number of sites.

After reading Camarena’s post, I decided to experiment a bit to see if it was possible to bypass paywalls simply by not running JavaScript. I mostly don’t care about paywalls because the majority of the sites that use them don’t have content that’s worth the effort of avoiding them. Still, I thought it would be interesting to test if the strategy was feasible.

I did this by opening any site that popped up a paywall in EWW. It worked for a surprising number of sites. Again, it’s almost never worth the effort but if you happen upon an article that you really want to read on a site that wants you to sign up for an outrageously expensive subscription, it may be worthwhile seeing if you can open it in EWW,

The other thing I learned is that reading content with EWW can be a very restful experience. No ads, no blinkenlights, and sometimes, no paywall either. I didn’t try running EWW with eww-readable but that would probably make the experience even more restful.

-1:-- EWW As A Way To Evade Paywalls (Post Irreal)--L0--C0--2026-05-20T12:34:18.000Z

TAONAW - Emacs and Org Mode: It's official: I prefer Inkwell over Elfeed

Last night I realized two things:

  1. I haven’t touched Elfeed in about a month
  2. I’ve been reading and interacting more with people’s posts than ever As I was looking at my Inkwell’s RSS feeds and cleaning up, I couldn’t help but notice how nice it looks:
A reading interface displays a list of posts on the left and an RSS subscription management panel with various feeds on the right.

And, yes, I prefer it over my list of feeds in elfeed, which are stored in an .org file - essentially lines of text with comments and tags.

I’m pretty sure this is the opposite case for most folks who use Emacs. First, Emacs users want to use Emacs more, not less, and second, Inkwell is not available without Micro.blog1.

But I think this is the point I’m getting at: Inkwell belongs in Micro.blog; actually, it is Micro.blog.

When I started using Micro.blog three years ago, I considered it mostly an alternative to running my own static site with Hugo, between fixing issues with Hugo, my CSS, Netlify and understanding attempting to understand git and Magit. Yes, Micro.blog is an alternative to all of that, but it isn’t just a blogging platform; It’s a definition of a contemporary blogger.

If you look at Micro.blog’s set of tools, you’ll see what I mean: it contains tools to keep track and post about books, movies and TV shows, private (encrypted) notes, photos and self-made video clips2, save articles and qoutes from around the internet (pocket style), automatic integration with other social media where possible - all of this around your hosted blog, complete with plugins and a theme (and let’s not forget the AI integration, if you want it and turn it on) you can tweak and take with you - your posts, media, css, everything - wherever you go.

And Inkwell adds an important direction to this mix.

My blogging hour in the morning now continues where I left off the night before, with saved highlights and complete articles from other people I keep track of. The integration between Inkwell and Micro.blog, where my reading turns into writing, still requires some work as the UI and some of the bugs get sorted out, but it’s there. And it’s already better and more intuitive for me than Elfeed, which takes place in its own isolated space.

Elfeed is very good at what it does (and hopefully, what it will keep on doing, with its creator leaving Emacs), and it has been good to me. It still is. But Inkwell, Micro.blog, and my recent adventures with finding out more bloggers and learning more about the Indieweb feel like an evolution. It’s the next step of whatever I’m doing here.

Footnotes

1: I recall Manton borrowed the idea from a different RSS reader, but I can’t find the reference right now

2: Finding an alternative to YouTube these days is not easy, and if you’re not trying to “build a brand” and repeat the chant of “click and subscribe,” the only semi-reliable alternative that comes to mind is PeerTube and (maybe Dailymotion?) - but Manton found a way that seem sustainable, at least for now.

-1:-- It's official: I prefer Inkwell over Elfeed (Post TAONAW - Emacs and Org Mode)--L0--C0--2026-05-20T12:17:42.000Z

Charlie Holland: Annotate-in-Place Notes with Emacs and org-remark

1. About   notes annotations emacs orgRemark

annotate-in-place-banner.jpeg

Figure 1: JPEG produced with DALL-E 3

I'm like most people when it comes to reading and note-taking.

Whether I'm new to a subject or fluent in it, I find myself devouring massive helpings of the seemingly infinite corpus of relevant text online, clamouring for some way to annotate, reason about, and synthesize that information.

Regardless of my level of mastery in a given subject, I've found that the rate of my information consumption has outpaced the capabilities of my note-taking system.

My dysfunctional note-taking process has been plagued by 2 main pain points:

  1. context switching (from the source content to the notebook).
  2. tenuous connections (between the source content and the notebook).

These issues have imposed an unnecessary friction on my learning process, and so I feel compelled to demonstrate my current workflow, which I find to be simple and cognitively ergonomic. In this post I want to introduce the specific but very generalizable pattern that enables my new workflow, annotate-in-place, and one elegant implementation of it in Emacs via nobiot's org-remark.

What makes this pattern so elegant to me is the familiarity of its experience. I don't know about you, but I've been annotating books and taking notes with pencils and pens, directly on the page, for almost my entire life, and this is often the most engaging and soul-lifting experience. There is a je ne sais quoi in this interaction that makes me feel closer to, if not part of, the thing I'm reading. This is a physical annotate-in-place, and it works beautifully.

I've been long searching for a cognitive bridge between the ergonomics of putting pen to source text and the infinite flexibility of a software solution. annotate-in-place is the pattern that provides that bridge, and org-remark in Emacs is one implementation of that pattern. With it, digital note taking feel as intuitive and ergonmic to me as note taking on a physical medium.

As a more cognitive benefit, I've found that annotate-in-place's reduction on the memory and organization burden of note-taking lets my mind expand into the internet, unincumbered by any friction of recording notes or worry that I'll forget to review them. That's a great feeling!

The first half of the post is about the pattern, in the abstract, of annotate-in-place. The meat and potatoes is a demo of org-remark in Emacs across a handful of contexts. I wrap up with some caveats of my current approach, and some hypotheses on why this approach is relevant beyond Emacs.

2. The Video: org-remark in Action   video demo

The upper-right of my Emacs (in the tab-bar) shows the keybindings and command names I am invoking, so you can map what you see onto your own configuration.

3. The Problem with Modern Digital Note-Taking   notes problem

We builders are often taught that coupling is bad, bad, bad…. But in some rare cases it makes perfect sense.

Most digital note-taking approaches decouple the note from the source. That's bad decoupling in my opinion. I'm guilty of this. I typically read in one app and write in another. Pure on-book annotation is an exception, but once I factor in something like a 'knowledge base' (a personal notes graph — think Obsidian, Roam, Logseq, org-roam, denote), I'm dealing with decoupled artifacts: the source artifact (abstractly, the 'site') and an annotation artifact (abstractly, the 'notebook').

In this context 'sites' can be a webpage, a book, or even your own notebook; and 'notebooks' can be a digital note app, or a physical piece of paper.

Everyone reading this (I assume) has tasted the vinegar of this decoupling pickle, but here are a few issues that stand out for me:

3.1. The Context-Switching Tax

The friction of context switching between site and notebook is small on a per-action basis, but it adds up, and it tragically punishes the virtuous act of noticing. Noticing, as passive as it sounds, is our intellectual leverage as special humans, and I believe it should be met with as little (ideally zero) friction as possible. I want to let my 'noticing' perform its magic, unbounded by the friction or imposition of my tooling or note-taking workflow.

3.2. Source Amnesia and Note Amnesia

I often find myself accumulating notes completely detached from the source they came from. When I revisit my notes months later, I find myself hunting for the source the notes were taken from. Vice versa, when I revisit the source, I similarly find myself in search for the notes that I took on that source, sometimes struggling to remember if I ever did record those notes in the first place.

I find this is a more significant problem when I revisit a source (note amnesia). In the best case, if I did take notes then it's possible that I wrote down the title of the source, or perhaps even the URL. That unidirectional implicit or explicit link can save me when I'm reading notes. But when I'm revisiting a source, there's nothing embedded in the source itself to let me know that some highlights or notes exist for it, and so in those cases, I never recover the precious memories I recorded.

3.3. No Signal on Revisit

When I return to the source (potentially months or years later) nothing tells me what past me found interesting. The blank source looks the same as it did the first time I visited it. I've likely lost familiarity with the source material or failed to review the relevant notes for that source before revisiting, so my brain has to do significant work just to resurface what I already found salient and recorded. And that's before the even harder, more important, work of refamiliarizing myself with its concepts or synthesizing it with something else I learned or realized in the meantime.

3.4. Memory Anxiety

If you're like me, you probably carry a low-grade worry about whether you can ever review what you covered across the many daily hours of reading complex source material.

Most second-brain systems compound this by encouraging capture without robust bi-directional links between the source and the notes. org-mode's capture offers a uni-directional link (in the notes), but the captured data never surfaces when I revisit the source from which I captured that information. I basically have to know somehow that the notes exist.

By contrast, when I annotate a physical book, the marks stay on the page. For me personally, this makes note taking on physical media worry-free because I know that all my highlights and marginalia will remain there and will shine brightly back at me when I re-crack that book or paper open. On re-reads, my eye is drawn to exactly the passages that mattered to me the last time.

4. Annotate-in-Place: The Pattern   pattern

This pattern, like most truly useful ones, is simple and elegant.

With annotate-in-place, when I find something worth marking, I highlight it in a single easy motion, as if it were a physical document. The highlight is visible the next time I visit the source, and a separate notes file is updated in the background with an entry containing three core fields plus optional metadata:

  1. The excerpt (so the verbatim source quote survives if the source disappears).
  2. A link back to the source, with enough location information to find the exact passage.
  3. Any commentary I choose to attach.
  4. Optional (configurable) metadata (timestamps, tags, etc…).

Everything else I might want to do with these notes (search, tag, daily review, integration with a knowledge base) is made possible by those recorded fields. The pattern's elegance comes from how little it asks of me at note-taking time, and how much it makes available to me at review or search time.

I've already expounded upon the complexity of reading and note-taking. Annotate-in-place comes to my rescue by making sure that the extra work of 'noticing' on my part is astronomically close to zero. All I have to do at that glorious notice moment is point and highlight, as if the document were as ergonomic as physical entity.

5. What Existing Tools Get Right (and Wrong)   readwise hypothesis

A few tools already implement annotate-in-place, but each is bounded by its environment. A couple I've used in the past:

  • Readwise offers in-browser highlighting (via browser official browser extensions) that syncs to Obsidian, Roam, Notion, and others. Its companion read-it-later app, Readwise Reader, extends the same model to PDFs, EPUBs, emails, and YouTube within Readwise's own apps, with strong mobile support and OCR that Emacs cannot match out of the box. This works really nicely (and was my first adventure into the annotate-in-place pattern), but the annotation environments are still Readwise's own, and scoped to the browser. What's more, to annotate any non-web-page content, I have to upload it to Readwise's servers for processing before I can mark it up. Readwise lacks support for annotating documents on your personal computer, like code files, org files, etc….
  • Hypothes.is does the same thing in the browser with shared annotations and a public web layer that no Emacs tool offers (yet) but is similarly scoped: highlighting only happens on web pages.

An interesting observation I made after using both is that, for me, the plurality of what I read is not a web page. Often times, it's RSS items in a feed reader, code in my editor, transcripts of chats with an LLM, Emacs's info pages, ebooks, mail, dictated notes, papers in PubMed, articles in my read-it-later tool (wombag), etc…. None of these polyhedral pegs fit into the round holes of Readwise or Hypothes.is, so I find myself pushed back into brittle copy-paste workflows and decoupled site+notes unless I'm reading in an app they support.

What I'm really after is an implementation of the annotate-in-place pattern that accommodates all these sources.

6. org-remark in Brief   orgRemark emacs

org-remark is the closest Emacs gets to a faithful implementation of the annotate-in-place pattern. It works on any text buffer. In other words, it works anywhere Emacs renders text (so everywhere) and it stores each highlight in an org-mode notes file that I own (no third-party intermediary like Readwise or Hypothes.is).

The command surface to achieve this is pleasingly small:

  • org-remark-mark-default marks the active region in the source (wherever that is) with a highlight overlay (the command name comes from the pen — see the next section). An entry appears in the corresponding notes file with the excerpt, a link to the source, and any metadata the pen has been configured to attach.
  • org-remark-open jumps from a highlight to the corresponding entry in the notes file, where you can write commentary using the full power of org-mode.

Of course, the notes file is an ordinary org file and presents in an ordinary Emacs buffer. As such, every existing org or Emacs tool (org-agenda, org-roam, denote, ripgrep, your own scripts, etc…) is available to help you search, navigate, and digest the information therein.

The killer feature of annotate-in-place for me is that when I reopen the source buffer later, org-remark displays the overlays at the correct positions. This is the thing that bridges the gap between the ergonomics of annotating on physical media and the feature-richness of note-taking in digital media. It also makes the link between the source and the notes bi-directional. So, I get the benefit of decoupling the note from the source, yet I retain the intuitive behavior of highlighting and annotating source material in-place.

6.1. Pens and Metadata   pens 

A pen in org-remark is basically a named highlighter, and each pen can attach arbitrary properties to its highlights. In my config of org-remark I define a default pen that timestamps every new highlight with a date link in Logseq's preferred format:

(org-remark-create "default"
                   'org-remark-highlighter
                   `(CATEGORY "important"
                     org-remark-highlight-date ,(my/org-remark-get-date)))

Calling org-remark-create defines a marker command named after the pen (here, org-remark-mark-default), which is what I then bind to a key. The date in the snippet is computed dynamically at mark time, so every new highlight automatically carries a link to its day. This, among other things, turns my notes files into a reviewable timeline (more on that in the daily review section).

Note that you can define as many pen commands as you like using org-remark-create. I get by with just one, but I can imagine use cases for having multiple which I wont elaborate on (exercise for the reader and all that 😜).

7. Extending org-remark to New Modes   extension elfeed wombag pubmed

org-remark ships built-in support for a few major modes, but it can be easily extended to support any arbitrary new mode. To do this, you implement two functions, register them on hooks, and optionally arrange for org-remark-auto-on to fire when the mode opens a buffer (that's what makes the highlights reappear when you revisit a source). Concretely, for a mode foo-show-mode (think elfeed-show-mode for RSS items, wombag-show-mode for read-it-later articles, pubmed-show-mode for PubMed papers), you need:

  1. A function that returns a stable file name for the buffer's content. This is what org-remark uses to find the right notes file when the same content is reopened. Hook it onto org-remark-source-find-file-name-functions.
  2. A function that returns a link back to the source. Hook it onto org-remark-highlight-link-to-source-functions.
  3. A way to turn org-remark on when a buffer of this mode appears. This is either an :after advice or a mode hook calling org-remark-auto-on.

Some modes can be tricky, but in general, I've found that this is a lot simpler than it sounds. Here is the elfeed integration, from my config, in roughly 30 lines of elisp:

(define-minor-mode org-remark-elfeed-mode
  "Enable Org-remark to work with elfeed.el"
  :global t
  :group 'org-remark-elfeed
  (if org-remark-elfeed-mode
      ;; Enable
      (progn
        (add-hook 'org-remark-source-find-file-name-functions
                  #'org-remark-elfeed-find-file-name)
        (add-hook 'org-remark-highlight-link-to-source-functions
                  #'org-remark-elfeed-highlight-link-to-source))
    ;; Disable
    (remove-hook 'org-remark-source-find-file-name-functions
                 #'org-remark-elfeed-find-file-name)
    (remove-hook 'org-remark-highlight-link-to-source-functions
                 #'org-remark-elfeed-highlight-link-to-source)))

(defun my-advice-elfeed-show-mode-org-remark (&rest _args)
  (org-remark-auto-on))

(advice-add #'elfeed-show-entry
            :after #'my-advice-elfeed-show-mode-org-remark)

(defun org-remark-elfeed-find-file-name ()
  (when (equal major-mode 'elfeed-show-mode)
    (my-org-remark-transform-org-link-to-filename)))

(defun org-remark-elfeed-highlight-link-to-source (filename _point)
  (when (equal major-mode 'elfeed-show-mode)
    (org-store-link nil)))

(org-remark-elfeed-mode)

The PubMed and Wombag integrations look the same (feel free to explore my configuration). This is the part of org-remark I find most enabling: the protocol for adding a new mode is small enough that the juice is typically worth the squeeze.

8. A Daily Review Workflow   review

Because every highlight is stamped with a date link, reviewing what I read today is just a simple grep for that timestamp in my notes directory. I search my highlights directory for the current day's link and get back exactly the passages I found interesting today, each with any commentary I wrote and a working link to the source. My video demonstrates this workflow.

For me, this completely eliminates the anxiety of reviewing anything I've read, and allows me to read more expansively and feverishly. I don't have to remember anything I'm reading because the timestamped entry created by org-remark does the remembering for me.

There are two adjustments you may want to consider to make this work well in your own system:

  • Persist highlights in a stable directory. Mine live under ~/logseq/pages/, but a single directory of any kind is enough. rg or grep against the date link in this directory is the review query. As a bonus, note that if you sync your knowledge base across machines, the persistent in-place highlights will show up on all the machines to which you synced your knowledge base.
  • Pick a date link format your knowledge base understands. I use Logseq's [[Mar 4th, 2026]] form so the same link doubles as a backlink in the rest of my graph, but [[2026-03-04]] works equally well in org-roam or denote.

9. What org-remark Gives You   benefits orgRemark

Beyond the pattern-level wins already covered, org-remark itself contributes some specifics worth naming:

  • Notes are cited and attributed by default. The link to the source is automatic.
  • Capture is cheap. The action is "select region, hit a key". The excerpt, timestamp, link, and notes-file entry are all created without my involvement, and my in-place highlights show up the next time I visit that source.
  • Annotations are first-class org data. Anything you can do in org (which is a whole lot) you can do under any highlight.
  • Notes integrate with the rest of your knowledge base. Because the output is plain org, denote, org-roam, and Logseq all treat my notes files like any other node in the knowledge graph.
  • Configurable everything. Pens, metadata, the on-disk location of the notes file, the link format, the highlight face, and almost any behaviour of the setup are all configurable. See org-remark's documentation for more details.

10. Caveats   caveats

There are some caveats to going whole-hog on this pattern in Emacs with org-remark.

  • JavaScript-heavy web pages. eww cannot render modern SPA-style pages, so I cannot highlight inside them directly. My fallback is to clip the page to a read-it-later tool (in my config, Wombag) that produces a clean text view org-remark can annotate. Readwise also remains a reasonable browser-side fallback for the cases where neither approach works.
  • PDFs. org-remark does not support PDFs. For PDFs, the annotate-in-place option in Emacs is pdf-tools, which lets you add annotations directly inside the PDF buffer. org-noter is the spirit-equivalent for tying org notes to PDF/EPUB locations side-by-side rather than in place, and its daily-review workflow transfers with minimal adjustment.
  • Drifting source text. org-remark relocates highlights using the persisted excerpt when the underlying buffer changes, but heavily-edited files (or web pages that change between visits) can still produce orphans. The notes file always has the excerpt, but the overlay may need re-anchoring. Helpfully, if a highlight has drifted, you get a nice indicator in the source buffer letting you know that has occurred. This is a limitation of all annotate-in-place tools, by the way, and in my opinion, org-remark handles it most gracefully.
  • Emacs lock-in. The org-remark tool is Emacs-only. The pattern is not (read on). If you have not moved into Emacs, see the closing section: Readwise and Hypothes.is together implement the annotate-in-place pattern really well, and the workflow you build around them will transfer if you ever do switch to org-remark in Emacs.

11. Closing: The Pattern Is the Point   closing

To wrap up, I want to close not on org-remark specifically, but the annotate-in-place pattern.

In Emacs the implementation is especially complete because Emacs treats every reading surface as a text buffer. Outside Emacs, those same four fields (excerpt, link, commentary, optional metadata) are the right rubric for evaluating any annotate-in-place tool you adopt. I personally think these fields are necessary if you want to get leverage out of an annotate-in-place solution.

If you are not in Emacs, Readwise and Hypothes.is implement the pattern within the browser. I've used both and think they're great and worth using (in fact Readwise is still my fallback for when I can't do annotate-in-place within Emacs). If you are in Emacs, org-remark is worth thirty minutes of setup and a small amount of elisp per mode.

In either case, you still benefit from annotate-in-place.

12. TLDR   tldr

Most digital note-taking detaches notes from their sources. Annotate-in-place is the pattern of marking content where it lives, with the highlight visible on revisit and an excerpt+link persisted in a separate notes file. org-remark is the Emacs implementation: built-in support for eww, Info, nov.el ebooks, and plain files, plus a small extension protocol for adding new surfaces (elfeed, pubmed-show-mode, wombag, gptel chats, etc.). A timestamped default pen turns the notes file into a reviewable timeline: a daily review is a grep for today's date link. Caveats are JS-heavy pages (fall back to Wombag or Readwise), PDFs (use pdf-tools for in-place, org-noter for side-by-side), and Emacs lock-in itself. The tool is Emacs-only, but the pattern is portable.

-1:-- Annotate-in-Place Notes with Emacs and org-remark (Post Charlie Holland)--L0--C0--2026-05-20T12:05:21.000Z

Bozhidar Batsov: neat: a language-agnostic nREPL client for Emacs

I think I’ll take my REPL neat
My parens black and my bed at three
CIDER’s too sweet for me…

– Bozier

Last week I announced Port, a small prepl client for Emacs. Today I’m following it up with another small Emacs package. Meet neat, a tiny, deliberately language-agnostic nREPL client.

Why?

For years I’ve been hearing some version of the same request: “could CIDER work with my non-Clojure nREPL server?”. Babashka, Basilisp, nREPL-CLR, even some homegrown servers people built on top of nREPL for languages I’d never heard of.1 The answer was always the same kind of squishy “sort of, in theory, with caveats”, because while bare nREPL is genuinely language-agnostic, CIDER is not. CIDER was built for Clojure and assumes Clojure pretty much everywhere.

I always thought the right answer was “let’s gradually make CIDER more language-agnostic.” That’s the kind of plan that sounds reasonable until you actually try it.

The thing that pushed me over the edge was, oddly enough, building Port. Port is small, focused, and doesn’t try to be CIDER. Working on it for a couple of weeks reminded me how (deceptively) productive it is to start from a clean slate when the new requirements don’t match the assumptions baked into a mature codebase. Trying to retrofit CIDER into a language-agnostic shape would have meant fighting with every helper that ever assumed clojure.repl exists, every middleware contract cider-nrepl defines, every project-type heuristic that knows about deps.edn and project.clj and nothing else. A whole lot of “is the server Clojure, or is it the other thing?” branches. The Port experience reaffirmed that the right move for a genuinely different client is a new project, not a thousand cuts to an existing one.

So neat was born. The name is short, says what it does (it’s neat, both in the small-and-tidy sense and in the “no deps, no special assumptions, just the protocol” sense), and conveniently leaves room for puns I haven’t fully committed to yet. I might land on a backronym one day. For now it’s just “neat”.

What neat actually is

neat is a small Emacs nREPL client. The code is split across four files:

  • neat-bencode.el: bencode encode/decode.
  • neat-client.el: TCP connections, request dispatch, the standard nREPL ops.
  • neat-repl.el: a comint-derived REPL buffer.
  • neat.el: the entry point, customization group, and neat-mode minor mode for source buffers.

It only uses Emacs builtins. There are no external runtime dependencies, not even on clojure-mode, because neat doesn’t assume Clojure on the other end. If you write clojure-mode, fennel-mode, hy-mode, or anything else that talks nREPL, you turn on neat-mode in that buffer and it just works.

The connection routing is also intentionally library-friendly. There’s a buffer-local neat-current-connection override so downstream packages can implement their own routing logic, plus a global default for the simple “one server at a time” case that most people will want.

Capability discovery is done at connect time via the nREPL describe op. neat doesn’t hardcode “this server has completions, this one doesn’t” assumptions. If the server reports a completions op, the CAPF backend lights up (with type annotations next to each candidate, when the server provides them). If it reports lookup, eldoc starts working and M-. jumps to definitions via an xref backend. If neither is there, you still get a perfectly serviceable raw REPL.

Basic usage

Start an nREPL server. Anything that speaks the protocol will do. For a Clojure server:

1
2
3
4
5
clj -M:nrepl
# or
bb nrepl-server :port 7888
# or
lein repl :headless :port 7888

Then in Emacs:

1
M-x neat RET localhost RET 7888 RET

A REPL buffer pops up, the prompt follows the server’s reported namespace, and you can type expressions at it. Multi-line input works because RET only submits when the form parses as balanced under neat-repl-input-syntax-table (Emacs Lisp syntax by default, which is close enough for any Lisp). Input history is persisted across sessions.

If there’s a .nrepl-port file in the project, the prompt defaults to its contents, so M-x neat RET RET is enough to connect.

To evaluate from a source buffer, turn on the minor mode:

1
M-x neat-mode

The familiar bindings are there, intentionally compatible with what CIDER users expect:

Key Command
C-c C-e neat-eval-last-sexp
C-c C-c neat-eval-defun
C-c C-r neat-eval-region
C-c C-b neat-eval-buffer
C-c C-l neat-load-buffer-file
C-c C-z neat-switch-to-repl
C-c C-k neat-interrupt-eval
C-c M-n neat-set-ns
C-c C-d C-d neat-show-doc-at-point
M-. xref-find-definitions
M-, xref-go-back

neat-eval-buffer ships the buffer contents as an eval op; neat-load-buffer-file uses the standard load-file op instead, so the server can attribute file and line numbers to errors. Use the latter when you’re actually loading a file from disk and care about good diagnostics.

neat-set-ns sets the buffer-local neat-ns, which gets sent as the ns field on every eval op from that buffer. For languages where the namespace is declared in the source (Clojure’s (ns foo.bar), etc.), swap in a parser via neat-buffer-ns-function.

For juggling multiple connections, M-x neat-list-connections opens a tabulated-list buffer with one row per live connection, where you can set the default or disconnect interactively.

That’s roughly the whole user-facing surface today. There’s no jack-in command, no inspector, no debugger, no test runner. Likely there will never be, but if you need those you should probably be using CIDER anyways…

Should you use it?

If you write Clojure and CIDER works for you, keep using CIDER. It’s mature, full-featured, and supported, and I’m going to keep working on it for as long as people use it. Nothing about neat changes that.

But if you find yourself in one of these situations:

  • you write a non-Clojure language whose runtime ships an nREPL server, and you’ve been muddling through with a half-supported CIDER setup,
  • you write Clojure but you value minimalism and don’t need the full CIDER feature set,
  • you’re building an Emacs package that needs to talk nREPL and you want a small, dependency-free library to build on,2

then neat might be a better fit. It’s small enough that you can read the whole thing in an afternoon, and the library/UI split (neat-bencode and neat-client are perfectly usable from other packages) is genuinely designed for downstream consumers.

The bigger picture

neat is part of a broader push I’ve been chewing on for a while now: making nREPL a healthy multi-language ecosystem rather than a Clojure-only protocol. That push has three legs:

  1. An actual nREPL specification. The spec.nrepl.org draft is (will be) the formal version of what today is “whatever nREPL the project does”.
  2. Reference clients. neat is one. The point of building a deliberately Clojure-free client is that it stress-tests the spec. Anywhere neat ends up needing to special-case the server, the spec has a gap.
  3. A compatibility test suite. The parameterised integration suite in neat already runs the same assertions against multiple servers and surfaces real divergences (Clojure batching (println "hi") into a single out message where Basilisp emits two, for example). I’d like to grow this into a portable suite that any nREPL server can self-check against.

This is also why I keep teasing a “reference CLI client” in conversations. An editor client is one thing, but a small command-line nREPL client written in a non-Lisp language would be a much sharper test of how language-agnostic the protocol really is. neat is plausibly a precursor to that. Time will tell how far I push this; for now I just wanted to get the Emacs side moving.

Thanks

As always, big thanks to Clojurists Together and everyone supporting my open source work. You make it possible for me to keep tweaking and improving CIDER, nREPL, clj-refactor, and friends, and occasionally try something “neat” on the side. neat isn’t replacing any of the existing Clojure tooling for Emacs. It’s just another tool in the box for the people who want it.

Feedback, ideas, and contributions are most welcome over at the issue tracker.

Keep hacking!

  1. https://github.com/clojure-emacs/cider/issues/3905 ↩︎

  2. For a long time I planned to extract CIDER’s nREPL client code into a reusable package, but now that we have neat I probably will finally abandon this idea. ↩︎

-1:-- neat: a language-agnostic nREPL client for Emacs (Post Bozhidar Batsov)--L0--C0--2026-05-20T06:00:00.000Z

Protesilaos: Emacs: Denote version 4.2.0

Denote aims to be a simple-to-use, focused-in-scope, and effective note-taking and file-naming tool for Emacs.

Denote is based on the idea that files should follow a predictable and descriptive file-naming scheme. The file name must offer a clear indication of what the contents are about, without reference to any other metadata. Denote basically streamlines the creation of such files or file names while providing facilities to link between them (where those files are editable).

Denote’s file-naming scheme is not limited to “notes”. It can be used for all types of file, including those that are not editable in Emacs, such as videos. Naming files in a constistent way makes their filtering and retrieval considerably easier. Denote provides relevant facilities to rename files, regardless of file type.

Below are the release notes.


Version 4.2.0 on 2026-05-20

This version brings several improvements to the core denote package as well as all the Denote extensions I maintain. The core package is stable, its feature set is rich, and the wider ecosystem of extensions is growing.

Most of the changes documented herein are of interest to experienced users who may be looking for ways to refine their workflow. I recommend that new users start with the basics, as I explained them in the original video demonstration of Denote or as they are documented in the manual’s section for newcomers:

Remember that the release notes are true only at the time of publication. The single source of truth is the official manual.

Core Denote

Overview of the new features

  • The command denote-dired-focus will filter the results of an existing denote-dired buffer. Use this to narrow down the results.

  • In Org files, the denote: link type can now be previewed using the built-in org-link-preview command, starting with Org version 9.8.0.

  • The command denote-link-or-create-with-command extends the existing convenience functions of the “do or create note” kind.

  • The denote-file-prompt uses completion metadata to sort by most recently accessed, group by directory or file extension, and cover packages that display cosmetic icons alongside completion candidates.

  • Denote now enforces a controlled vocabulary for keywords when denote-infer-keywords is set to nil, such that only the denote-known-keywords are provided as an option at the relevant prompts.

  • The mechanism for integrating Denote with org-capture now supports prompting for an signature via denote-org-capture-with-prompts (the signature is an optional, free-form component of the Denote file-naming scheme).

  • Several packages that extend Denote are documented in the manual. If you have a package for Denote, let me know and I will write a section about it.

Focus a denote-dired buffer with denote-dired-focus

The command denote-dired produces a Dired listing of file names that match the given regular expressions. Users can benefit from the Denote file-naming scheme to, for example, include all files that have the keyword _emacs. In the resulting Dired buffer, the new command denote-dired-focus can then be invoked to further narrow down the results, such as to only show files that have 2026 in their file (with default settings, the date is part of the Denote identifier).

I implemented this feature in response to issue 693 by 82Kang: https://github.com/protesilaos/denote/issues/693.

Improvements to the file prompt

Various Denote commands prompt for a file name: for instance, denote-link asks which file to link to. This file prompt is now augmented with completion metadata that transform how files look and how the information is organised.

Before, the prompt presented full file names like:

20220610T043241--initial-thoughts-on-the-zettelkasten-method__notetaking.org
20220610T062201--define-custom-org-hyperlink-type__denote_emacs_package.md
20220610T162327--on-hierarchy-and-taxis__notetaking_philosophy.txt

Those same file names are now transformed to look like this:

2022-06-10  initial-thoughts-on-the-zettelkasten-method  notetaking
2022-06-10  define-custom-org-hyperlink-type  denote_emacs_package
2022-06-10  on-hierarchy-and-taxis  notetaking_philosophy

The files will be grouped by file extension or directory (if they are in a subdirectory of the denote-directory). Furthermore, they will be sorted by most recently accessed.

The underlying file names are still available except that their presentation is modified. This means that input at the minibuffer prompt will still match everything they contain.

This completion metadata extends to the packages all-the-icons and nerd-icons, which are now instructed to add the correct file icons to the completion candidates: an Org file will have the unicorn icon beside it, for example.

Users who do not like the new style can revert to the plain presentation by setting denote-file-prompt-extra-metadata to nil.

Advanced users who wish to set up the completion-category-overrides may target the denote-file completion category or, anyhow, modify the denote-file-prompt-extra-metadata.

Link to a file or create a new note using a specific command

Denote provides many “convenience wrapper” commands that do something quickly which can also be achieved with minimal configuration. For example, the denote command may be modified to also prompt for a file type and so the denote-type command is like denote with the addition of the file type prompt. Users can look at the source code of denote-type to write their own small variations (the manual provides several examples as well).

The denote-open-or-create-with-command may then use those to implement its specified behaviour of “open an existing file or create it using a convenience wrapper command”.

Same principle for the new denote-link-or-create-with-command: it makes possible the workflow of “link to an existing file or create a new note with the given command”.

Convenience wrappers are listed in the value of the user option denote-commands-for-new-notes.

Thanks to Matthew Batson for building on top of existing functionality to contribute denote-link-or-create-with-command in pull request 674: https://github.com/protesilaos/denote/pull/674. Matthew has assigned copyright to the Free Software Foundation.

Preview denote: links in Org files

Starting with Org version 9.8.0 custom link types such as denote: can implement their own preview mechanism. In practice, this means that denote: links pointing to image files will now work as expected with org-link-preview (remember that the Denote file-naming scheme can be applied to any file and is in no way specific to note-taking—I use it for documents and videos, for example).

Thanks to Samuel W. Flint for the original contribution in pull request 683: https://github.com/protesilaos/denote/pull/683, with further changes by me. The original contribution is small, meaning that Samuel does not need to assign copyright to the Free Software Foundation.

Signature support in Org capture

The denote-org-capture-with-prompts function now supports the signature file name component as an additional parameter. This function is meant to be used in tandem with the org-capture mechanism, as shown in the manual.

Thanks to Tobias Lidman-Strauss for the contribution in merge request 2 on the GitLab mirror: https://gitlab.com/protesilaos/denote/-/merge_requests/2. The change is small, meaning that Tobias does not need to assign copyright to the Free Software Foundation.

The denote-fontify-links-mode is only relevant for .txt files

The denote: links are automatically highlighted as links in Org and Markdown bufers. Users who prefer to write notes in plain .txt files must enable the denote-fontify-links-mode to get the same effect.

I have revised denote-fontify-links-mode to only work with .txt as its other users were not necessary. In the process, I have deprecated the denote-fontify-links-mode-maybe function: just use the denote-fonftify-links-mode.

The keys RET and C-c C-o open the link (same keys used by Org and Markdown modes).

Growing ecosystem of Denote packages

In the Denote manual I mention packages that build on top of Denote. There is one section for each package. The manual now includes the following:

  • denote-agenda (by Samuel W. Flint): Use Denote notes as Org agenda files.
  • denote-journal-capture (by Samuel W. Flint): Enhanced journaling workflows.
  • denote-lint (Peter Smith): Checks for inconsistencies in Denote file names and front matter.
  • denote-project-notes (by Samuel W. Flint): Integrate Denote with Emacs’ built-in project support.
  • denote-regexp (by Samuel W. Flint): Search and link notes using regular expressions.
  • denote-review (by Matto Fransen): A package for reviewing notes over time.
  • denote-sections (by Samuel W. Flint): Manage sections within Denote notes.
  • denote-wordcloud (by Alexander Kuzmin): Generate word clouds from Denote notes.

Miscellaneous

  • The command denote-dired (alias denote-sort-dired) is refactored to work as intended in all cases. Thanks to kilesduli for the contribution in pull request 666: https://github.com/protesilaos/denote/pull/666. Further changes by me, including the option to maintain many separate denote-dired buffers, which I did in response to issue 693 by 82Kang: https://github.com/protesilaos/denote/issues/693.

  • I have revised the denote-grep mechanism and all of its ancillary functions and variables are revised in the interest of consistency and maintainability. Thanks to gnuhack for contributing a macro that was meant to streamline some commands. This was done in pull request 697: https://github.com/protesilaos/denote/pull/697. I eventually changed lots of things so that the macro was not relevant anymore, though mine was a change with a wider scope.

  • The Org link storage mechanism (denote-link-ol-store) now works correctly within org-capture buffers, allowing for more flexible linking workflows.

  • Following non-Denote Markdown links no longer result in an error under certain circumstances. Thanks to bplubell for the contribution in pull request 685: https://github.com/protesilaos/denote/pull/685. The change is small, meaning that its author does not need to assign copyright to the Free Software Foundation.

  • Retrieving front matter is now more reliable, even when the buffer is unsaved. Thanks to kilesduli for the contribution in pull request 672: https://github.com/protesilaos/denote/pull/672. Also thanks to Jean-Philippe Gagné Guay for reviewing the change and for reporting a problem with an earlier version of the code in issue 670: https://github.com/protesilaos/denote/issues/670. Further changes by me.

  • The various Denote rename commands that affect the front matter in files no longer change existing spacing. I did this to address the comment posted by Morten Kjeldgaard in issue 703: https://github.com/protesilaos/denote/issues/703.

  • Updated the documentation to explain how to automatically encrypt new notes when using a custom file type.

  • Refined the internal helper functions for directory management and identifier validation.

  • Thanks to nescias for fixing three typos in the manual. This was sent to me as a patch, which I installed as commit c772378.

Changes to the extensions of Denote I maintain

This is about packages I maintain. Some of them were originally part of the denote.git repository, but I moved them out into their own packages to make everything easier to reason about.

consult-denote version 0.5.0
denote-merge version 0.1.0

This is an optional extension to the denote package. It provides commands and relevant user options to streamline the work of merging contents from one Denote file to another. This is for users who periodically review their notes to add, remove, or otherwise consolidate their accumulated knowledge.

denote-journal version 0.3.0
  • Package name (GNU ELPA): denote-journal
  • Official manual: https://protesilaos.com/emacs/denote-journal
  • Git repository: https://github.com/protesilaos/denote-journal
  • Backronym: Denote… Journaling Obviously Utilises Reasonableness Notwithstanding Affectionate Longing.

  • The user option denote-journal-keyword now supports a nil value, allowing users to create journal entries without a specific keyword. Thanks to nescias for sending me the patch via email, which I installed as commit d4cc501 in denote-journal.git. The change does not require copyright assignment.

  • Fixed an issue about how the function denote-directory-files was used. Thanks to Donald Brady for reporting the bug in issue 656 on the main Denote repository and to kamchy for confirming the problem: https://github.com/protesilaos/denote/issues/656. The approach was utlimately revised in denote.git courtesy of a change by Jean-Philippe Gagné Guay in pull request 661: https://github.com/protesilaos/denote/pull/661.
denote-markdown version 0.3.0
  • Package name (GNU ELPA): denote-markdown
  • Official manual: https://protesilaos.com/emacs/denote-markdown
  • Git repository: https://github.com/protesilaos/denote-markdown
  • Backronyms: Denote… Markdown’s Ambitious Reimplimentations Knowingly Dilute Obvious Widespread Norms; Denote… Markup Agnosticism Requires Knowhow to Do Only What’s Necessary.

  • The package defines a markdown-obsidian file type which can be used by relevant note-creating commands, such as denote or the convenience wrapper denote-type. This file type is updated to be more robust, in accordance with some changes in core Denote (I am not even documenting those, as they are not intended for users).
denote-org version 0.3.0
denote-silo version 0.3.0

The minibuffer prompt for silo directories uses the corrent completion category (consistent with what I mentioned above about completion metadata). Thanks to Wilf-bog for reporting an error with the completion prompt in issue 1: https://github.com/protesilaos/denote-silo/issues/1.

denote-sequence version 0.3.0

This package deserved its own release notes, as I did a lot of work on it. But as this file is already long, I will focus on the essentials:

  • The denote-sequence-scheme used to support a numeric and alphanumeric option. There now is a third one called alphanumeric-delimited. It combines features from the other two and may be better suited for especially long/intricate sequences.

  • The denote-sequence-reparent command now works recursively to produce the desired consequences to all descendants of a given sequence note. Thanks to Peter Prevos for the contribution in pull request 13, which further changes by me: https://github.com/protesilaos/denote-sequence/pull/13.

  • The command denote-sequence-view-hierarchy produces a bespoke buffer with all the sequence notes that form a hierarchy. The buffer displays file titles, the concomitant sequence, and file keywords. Each level of depth is expressed by a number of spaces, controlled by the user option denote-sequence-hierarchy-indentation. In the hierarchy buffer, there are commands that move to the next/previous item, or forward/backward at the same level of depth. RET opens the file at point, TAB folds/unfolds the tree. The user option denote-sequence-hierarchy-move-and-open controls whether motion commands should automatically open the file, which by default happens in the other window (users who modify the variable denote-open-link-function will get the specified behaviour in this context as well). The denote-sequence-view-hierarchy can be called with one or two prefix arguments to limit to a given sequence prefix and/or level of depth (something that denote-sequence-dired also supports). In short, this is a way to visualise your sequence notes in a buffer that has a different presentation than Dired.

  • Thanks to alan-w-255 for renaming and refining a prompt that is also used in the hierarchy feature. This was done in pull request 15: https://github.com/protesilaos/denote-sequence/pull/15. The change is small, meaning that its author does not need to assign copyright to the Free Software Foundation. Further refinements by me.

  • Thanks to Nicolas Semrau for binding q to quit-window in the denote-sequence-hierarchy-mode-map. This was done in pull request 20: https://github.com/protesilaos/denote-sequence/pull/20. The change is small, meaning that Nicolas does not need to assign copyright to the Free Software Foundation.

  • The denote-sequence-file-prompt-extra-metadata is the functional equivalent of the aforementioned denote-file-prompt-extra-metadata.

  • Thanks to liyingzhi for pointing out an inaccurate comment in the docstring of denote-sequence-scheme. This was done in issue 18: https://github.com/protesilaos/denote-sequence/issues/18.

  • The denote-sequence-dired is updated to align with the modalities of denote-dired, as noted above. Thanks to juh for reminding me about the need for changes in issue 14: https://github.com/protesilaos/denote-sequence/issues/14.

  • Thanks to Stefan Monnier for pointing out a stylistic mistake in an older version of denote-sequence-dired. This was done on the emacs-devel mailing list: https://lists.gnu.org/archive/html/emacs-devel/2025-11/msg01119.html. Also thanks to Stefan for telling me about some other compiler warnings: https://lists.gnu.org/archive/html/emacs-devel/2025-11/msg01119.html.

Git commits

~/Git/Projects/denote $ git shortlog 4.1.0..4.2.0 --summary --numbered
   184	Protesilaos
     4	duli
     3	Jean-Philippe Gagné Guay
     3	Matthew Batson
     2	alvmts
     2	gnuhack
     1	Alvin Hsu
     1	Matto Fransen
     1	Samuel W. Flint
     1	Tobias Lidman-Strauss
     1	bplubell
     1	gvalson
     1	nescias
-1:-- Emacs: Denote version 4.2.0 (Post Protesilaos)--L0--C0--2026-05-20T00:00:00.000Z

Dave Pearson: next-gh-pr.el v1.0.0

Pretty much every project that I actively maintain on my GitHub account has a change log of some description. For a long time now, whenever I add a new entry to the log, I'll include a link to the PR that implements that change. Inevitably, this results in me adding the ChangeLog entry, creating the PR, then doing a follow-up change and commit now that I know the PR number, which allows me to add the link.

So I've created next-gh-pr.el to save me just a little time and let me be just a little more lazy. Inside it I've currently got a next-gh-pr-insert-markdown-link command which, when run, as you might imagine, inserts a link to the next likely PR URL as Markdown.

Working out the next URL is simple enough: get the latest issue and PR number, take whichever is the highest, and add 1. There is the wrinkle that discussions also cause this number to bump, and getting the latest discussion number is a little extra faff that I can't be bothered with right now, but my projects very seldom have discussions taking place anyway.

-1:-- next-gh-pr.el v1.0.0 (Post Dave Pearson)--L0--C0--2026-05-19T15:43:33.000Z

Irreal: Marking Recently Modified Files In Dired

Marcin Borkowski (mbork) really likes all the ways you can mark files in Dired but noticed that an easy way to mark recently modified files was missing. He knows quite a bit about writing Elisp so it was an easy decision to decide to write some code to implement the missing feature.

The code, which you can see at his post, is pretty simple and easy to follow. What wasn’t so easy were some annoying design decisions. For example, what constitutes the current day? Is it 24 hours ago until now or is it the previous midnight until now? And by the way, should that be UTC or local time?

The natural interface is to specify the number of previous days you want to mark as a prefix argument but that leaves open the question of how to unmark the last n days. The natural solution—and the one mbork chose—is to use a negative n to mean “unmark the last n days”. So positive n, mark files modified in the last n days; negative n unmark file modified in the last n days. What about 0? Mbork made the arbitrary decision to have that mean mark files modified in the last 60 minutes.

There are a couple of other nuances that you can read about in mbork’s post. The real takeaway for me is how tricky it can be to get the small details right. That seems especially true when you’re dealing with time calculations. Questions like, “What, exactly, does ‘yesterday’ mean” turn out to be a lot harder to answer than they first seem. Take a look at mbork’s post to see what I mean.

-1:-- Marking Recently Modified Files In Dired (Post Irreal)--L0--C0--2026-05-19T15:10:36.000Z

Jakub Nowak: New Job: Jira Integration

I haven't been very active on this blog for the last few months. I've recently started a new job, and part of what I've been doing in my spare time is adding to my Emacs configuration to make some of the daily chores easier (or to remove them entirely).

If you know me, you know I'm not a fan of WebUIs, or just mouse-focused GUIs in general. Jira is no exception. Previously, I've had to deal with Jira's annoying click and drag nonsense and sort of dealt with it, but I've always wanted to be able to use it from within Emacs. Not just because that means no mouse-based WebUI, but also because it potentially means making custom automations around tickets. Enter the new job, where I'm able to make myself an API token, and therefore make use of org-jira for the first time.

You can see the config I've written around it here. This works basically exactly as expected, although I have had to do something a bit hacky to keep the API token properly stored. Storing the key on MacOS as recommended in the readme wasn't working for me, so instead I've stored it as a generic password. When launching Jira, this password is fetched into the kill ring to be pasted into the prompt if needed. This is kind of terrible, but it does work well enough.

(when (equal system-type 'darwin)
  (kill-new
   (string-trim-right (shell-command-to-string (concat "security find-generic-password -a \""
                                                     jiralib-user "\" -s \"jira\" -w")))))

You should be careful when storing the API token with add-generic-password, make sure you write it in the command with -w "<token>" and don't copy it into the prompt. When I was copying it into the prompt, the token was getting cut off, which was a pain to debug because Jira cloud doesn't have 401 errors for this sort of thing on the JQL search. You may also notice string-trim-right here: the output of shell-command-to-string includes the trailing newline, which will mess up the auth.

I'm also using my org projects space as the Jira workspace locally, which means I can use all the same organisation helpers as I do with my personal project files.

In terms of automations, org-jira already provides useful enough keybinds for progressing tickets, leaving comments, etc., and at the moment I don't feel like I need to improve there. However, since this Jira instance is integrated with Bitbucket, it's convention to use the ticket number when opening a new branch for work related to that ticket. That way Jira can show things like PR status, etc.

Because each Jira board or project only has one repository associated, I'm assuming that there will be only one directory for that project work, and that can be a customizable variable.

(defcustom jira-key-directory-alist '()
  "Directories associated with a particular project --- git repositories.
For example, (\"CBM\" . \"~/build/etc\") will use ~/build/etc for ticket-specific commands in the CBM project."
  :type 'alist
  :group 'jira
  :group 'theurgy)

Then this simple function fetches the Jira issue ID under the cursor, opens a magit status buffer in the appropriate directory, and starts branch creation.

(defun jira-branch-ticket ()
  "Create a branch from the current ticket, in the repository specified by `jira-key-directory-alist'."
  (interactive)
  (let* ((issue-key (progn
                    (org-jira-copy-current-issue-key)
                    (substring-no-properties (car kill-ring))))
       (project-code (car (split-string
                           issue-key
                           "-")))
       (project-dir (cdr (assoc project-code jira-key-directory-alist))))
    (magit-status project-dir)
    (kill-new issue-key)
    (call-interactively #'magit-branch-create)))

I'm not pre-selecting main/master as the origin here because it's possible that I may want to branch off something else. Nor am I pre-populating the branch name, just killing the ticket number, in case I need multiple branches per ticket.

Ideally, I would like to pre-populate the magit branch prompt with some editable default values, but I'm not actually sure how to do that, so this will do for now.

The next blog will look at the AWS CLI customisations I've built up, so stay tuned.

-1:-- New Job: Jira Integration (Post Jakub Nowak)--L0--C0--2026-05-19T00:00:00.000Z

Marcin Borkowski: Marking today’s files in Dired

As anyone reading my blog knows, I’m a big fan of Dired. One of its killer features is the set of marking commands, which allow marking files based on their extensions, names (regex-based), contents (also regex-based). There is also a “universal marking command”, dired-mark-sexp, which allows the user to provide an Elisp expression serving as a predicate and marks all files satisfying that predicate. What’s even more, you can use several symbols in that predicate, like size or name (head to the docs to learn more). What I found lacking is an easy (that is, not requiring me to type a convoluted expression each time) way to mark “recently modified” files.
-1:-- Marking today’s files in Dired (Post Marcin Borkowski)--L0--C0--2026-05-18T21:01:00.000Z

Sacha Chua: 2026-05-18 Emacs news

My favourite post this week was oantolin's tip about using Eww. It's always interesting to see what people can do when they apply Emacs's power and composability to all sorts of things, including evaluating code snippets from webpages. Outside Emacs, there was a lively conversation on HN about personal software. Enjoy!

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 e-mail me at sacha@sachachua.com.

-1:-- 2026-05-18 Emacs news (Post Sacha Chua)--L0--C0--2026-05-18T17:59:27.000Z

Charles Choi: Using the Mouse for Emacs Rectangle Commands

img

Of all the built-in editing commands in Emacs, the commands that work with rectangles delight me the most. Once understood, they can save effort in many situations.

That said, the biggest downside to rectangles is the amount of setup it takes to use them. As with many things Emacs, by default you have to memorize a bunch of keybindings to get anything done with them.

In Casual, I addressed the above downside by providing a Transient menu for rectangle commands. Since building that, I've come to use rectangle commands routinely. But even then, there is ceremony to set up a rectangle selection.

With my recent work on mouse-driven interactions in Anju, I’ve learned that rectangle selection is trivial via C-M-<mouse-1> dragging. Once selected, having a menu of rectangle commands makes working with them even easier. So I made one for the latest v1.4.0 update for Anju, now on MELPA.

The “Rectangle” sub-menu is available via the main menu bar “Edit” menu (as shown in the screenshot above) or via context menu. Using rectangle commands in conjunction with the align-regexp (“Edit › Align Regexp…”) and whitespace-cleanup (“Edit › Delete › Whitespace Cleanup”) can make short work of editing text that is laid out in columns. Anju makes both of these commands available from the main menu.

Side note: on using C-M-<mouse-1>, sometimes Emacs will only read M-<mouse-1> and do a secondary selection, leaving an unwanted highlight. Enter M-<mouse-1> to dismiss the highlight.

If you find Anju to be useful, please support its development by buying me a coffee. I’ve got a number of new features planned for it.

-1:-- Using the Mouse for Emacs Rectangle Commands (Post Charles Choi)--L0--C0--2026-05-18T16:45:00.000Z

James Dyer: VC-Mode Meets Magit - or Why I Finally Gave In!

I have been a VC-mode loyalist for years, it is built in, it is simple, it covers the basics - commit, push, pull, diff, all there with C-x v bindings. I never really felt the need for Magit, honestly. VC-mode just works, right?

20260518114325-emacs--VC-Mode-Meets-Magit-or-Why-I-Finally-Gave-In.jpg

Until it does not. Or rather, until you need something that is not quite available. As vc-mode is source code control agnostic then there were always going to be some limitations and my git usage is now starting to become a little more advanced.

Recently I hit a divergent branch situation, remote had moved on, I had local commits, and git refused to push, I reached for C-x v m (vc-merge) to pull in the upstream changes, and that worked fine as a merge. But what if I wanted a rebase instead? Clean linear history, no merge commits?

Turns out there is no vc-rebase at all in Emacs! You can use vc-pull and it will rebase if pull.rebase is set in your git config (I think, although I haven't tried it), but there is no interactive vc-rebase command to invoke directly. And vc-merge only merges, If you want a rebase, you have to drop to shell or configure git to default to it. I wanted something more cohesive, more discoverable, and #sigh, here enters magit, I used it a few years ago so I still had a residue of muscle memory, but that said, I am not abandoning VC-mode entirely. For quick operations, a single file commit, a blame, a quick diff – C-x v I still like vc-mode. Magit is great for repo-level operations; VC-mode is great for file-level ones. They complement each other nicely, and there is no reason to pick one over the other, this is Emacs!

I added use-package magit to my config with a C-x g binding, full-frame status display, word-granular diff refining, and also released C-w in the magit status map so my window-management prefix still works (small things, but they matter):

(use-package magit
  :bind ("C-x g" . magit-status)
  :config
  (setq magit-display-buffer-function
        #'magit-display-buffer-same-window-except-diff-v1)
  (setq magit-refresh-status-buffer t)
  (setq magit-section-initial-visibility-alist
        '((untracked . show)
          (stashes . hide)))
  (setq magit-diff-refine-hunk 'all)
  (define-key magit-status-mode-map (kbd "C-w") nil))
-1:-- VC-Mode Meets Magit - or Why I Finally Gave In! (Post James Dyer)--L0--C0--2026-05-18T10:43:00.000Z

Sacha Chua: May 29: Emacs Chat with Omar Antolin Camarena

On May 29, I'll chat with Omar Antolín Camarena about Emacs and Life.

(America/Toronto) = Fri May 29 1030H EDT / 0930H CDT / 0830H MDT / 0730H PDT / 1430H UTC / 1630H CEST / 1730H EEST / 2000H IST / 2230H +08 / 2330H JST

Related links:

This session will be recorded, and I'll update this blog post with notes: https://sachachua.com/blog/2026/05/may-29-emacs-chat-with-omar-antolin-camarena/

You can add the iCal for upcoming Emacs Chat episodes to your calendar. https://sachachua.com/topic/upcoming-emacs-chats.ics

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

View Org source for this post

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

-1:-- May 29: Emacs Chat with Omar Antolin Camarena (Post Sacha Chua)--L0--C0--2026-05-17T22:02:50.000Z

Irreal: May I Recommend: EWW

I see a lot of blog posts recommending EWW. Sometimes I even write about them. The common theme is something along the lines of, “No, you can’t really replace a full-fledged browser with EWW but you can do a lot and a ”real“ browser is only a keystroke away.”

In another May Emacs Carnival entry, Omar Antolín Camarena offers his reasons for using EWW. He agrees with the conventional wisdom that EWW isn’t a replacement for a normal browser but that it is useful in many situations and even has some advantages over your default buffer.

He believes that one of the chief advantages of EWW is that it doesn’t run JavaScript. That’s ironic, of course, because EWW’s lack of support for JavaScript is one of its most oft cited shortcomings. But Camarena says that lack is often an advantage because JavaScript is often used to load ads or a paywall or to reconfigure your display preferences often choosing low contrast colors that are hard for anyone but the young to read.

His second reason for using EWW is that it brings the power of Emacs to your Web browsing. Among the advantages he lists are:

  • You can easily resize images without changing font and other sizes.
  • You can read the Web site content in multiple columns using follow-mode.
  • You can use occur for a search and keep a list of results and easily navigate among them.
  • You can evaluate ELISP directly in the EWW buffer and many other language as well with a bit of plumbing.
  • You can use eww-readable to eliminate a lot of the junk that comes with many Web pages.

And, as Camarena stresses, you can always escape to a normal buffer with eww-browse-with-external-browser, bound to & by default.

-1:-- May I Recommend: EWW (Post Irreal)--L0--C0--2026-05-17T14:35:11.000Z

Sacha Chua: YE29: Sacha, Prot, and Philip Kaludercic Talk Emacs: Newcomer Experience

: Updated transcript

Philip Kaludercic wanted to continue the conversation from YE24: Sacha and Prot Talk Emacs - Newbies/Starter Kits. He's spent a lot of time thinking about this as one of the main contributors to newcomers-presets. We talked about newcomers-presets, the idea of a "reset theme" that lets experienced users pin defaults to a specific version of Emacs, upcoming changes, and working with emacs-devel.

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

Chapters

  • 0:00 Opening
  • 2:59 newcomers-presets user option theme; would be nice to explain what the changes are
  • 5:00 finding a balance between "it's fine the way it is" and "just use Doom Emacs"
  • 6:37 people value stability, but also conventions have shifted.
  • 6:50 ways Emacs does things differently: ex: terminal vs eshell, output is editable; new users want to edit the previous prompt; sometimes goes against people's intuitions
  • 9:21 How do people develop Emacs intuition? Immersion
  • 9:55 example: dabbrev, there's no undo? Ah, it's just the regular undo.
  • 11:00 newcomers presets: smooth over the intuition-disrupting things that are not actually necessary/beneficial; ex: enable which-key
  • 14:32 newcomers-presets choice is not saved at the moment
  • 17:08 newcomers without much computing experience might even find it easier (no C-c expectations, C-v etc)
  • 18:30 Focus group?
  • 22:15 Emacs survey before
  • 22:48 people's backgrounds influence their responses
  • 23:46 Hypothetical: Reset themes, to reset things back to the defaults of a specific Emacs version
  • 24:22 package-autosuggest-mode suggests based on file extension
  • 27:52 Emacs 32: bundled versions of Emacs (Big Emacs - distributions that include more packages)
  • 29:54 Selection versus multiple completion
  • 34:39 Manuals
  • 35:08 More examples?
  • 36:22 find-user-init-file?
  • 38:38 Getting over the reverence for Emacs's history
  • 40:11 Changes are more likely to happen when someone puts in the work to make a patch
  • 44:03 Preserving Git history of packages absorbed into the core
  • 46:00 Dealing with multiple types of Emacs
  • 48:09 Fat Emacs is just about bundling more packages from ELPA, not changing the configuration for them
  • 51:23 Customize
  • 54:41 CUA - Common User Access
  • 55:00 ini file format? https://sdf.org/~pkal//blog/emacs/ini-init.html
  • 55:10 Emacs configuration generator
  • 55:54 INI-style configuration
  • 1:00:21 Quick summary
  • 1:02:27 Continuing with INI
  • 1:04:42 Motivation
  • 1:06:50 Politics and philosophy
  • 1:09:23 Experimenting with things outside core
  • 1:10:42 Extending the core
  • 1:11:52 Guide to contributing to ELPA
  • 1:13:11 Making the newcomer experience better
  • 1:14:30 "user option themes" versus "appearance themes"
  • 1:15:24 find-library
  • 1:16:49 configuration generator in Emacs? maybe more wizards?
  • 1:16:59 Starter kits
  • 1:17:39 Configuration generator in Emacs Lisp?
  • 1:18:40 extending the archive format
  • 1:20:56 User interfaces

Transcript

Expand this to read the transcript

0:00 Opening

Sacha: I'm going to start recording. I'm going to do the thing. I'll let you know. Okay. Let's do this. Yeah.

Prot: Yeah.

Sacha: Yeah. Okay. Hang on a second. Starting, going live. Okay. So, hello, everyone. This is Yay Emacs 29. And today I am here with Prot and Philip Kaludercic. We're having this conversation about Emacs newcomer experience, which started off with an Emacs carnival last month about newbies and starter kits, which Cena started and you fleshed out with more questions. And now this is snowballing to, okay, let's figure out what we can do to make Emacs easier for newbies who are coming in, maybe they're non-developers who have heard good things about Org Mode, or maybe they're developers who want to try out what this Emacs thing is and what's all the fuss about having an editor that's been around for so long. Or maybe they're actually still VS Code or Vim fans, but they really just want to use Magit, so they're coming in just for that. A lot of different paths to coming into Emacs. We do have this live stream, so if people have questions, I will at some point figure out where the chat is on my screen so I can read them out to you. But my plan here is I'll just be in the background taking notes most of the time and interjecting with occasional questions. And maybe Philip and Prot, you can go brain dump all the wonderful things you've been thinking about the Emacs newcomer experience.

Philip: At this point, regret not having written down any notes from the last video or from your last recording of YouTube, because I noticed I had a few things I wanted to add or intersperse. But I guess we can take a look at two things. So first one is the state of introducing people to Emacs now. And the question there is, who are we introducing Emacs to? Just like you said, you sketched out a few different profiles of people who presumably have entirely different interests, motivations, like if someone wants to just use Magit like Emacs is there. It's the tool, it's the GUI that implements Magit, then these people have an entirely different motivation than someone who actually says, well, I'm coming at it from, I heard it's an interesting tool for free software development. Build your own or understand free software in a different sense, where you can actually do find-function and open the definition of the function you just used. I think malleable is the current catch word that people like to use in that context. So there's some issue in that sense.

2:59 newcomers-presets user option theme; would be nice to explain what the changes are

Philip: And then the specific comment from the last discussion which caught my attention was We were talking about Emacs 31, there's this preset theme, the newcomers-presets theme, which is implemented as a user option theme, or that's how I like to refer to it. And I probably should just briefly stop and say that everything I'm saying is from my own perspective. I don't feel comfortable saying that this is the Emacs-devel perspective or that any other of the Emacs developers necessarily have to agree with me. I just think that I might have a few things.

Prot: Sorry, I lost your audio. Just to say I lost your audio, Philip. Excuse me. Sorry, I lost your audio for a second. You could hear it fine. I will hear it in the recording.

Sacha: Okay, so basically, you can repeat it, I guess. Go ahead.

Philip: What did I say? So you were saying that... I'm not representing emacs-devel. These are my views which are informed by the discussions that we had in emacs-devel that I hope will be represented. I think I'm the maintainer of the preset theme, but of course other people are also contributing to it and adding other options. Specific points I had like the target audience of the preset theme was not people who would be particularly interested. What the options are. I think that was a discussion point last time. I admit it's a technical deficiency currently. There's no pretty way. I think it would be nice if we extended describe theme to actually list the options that are modified with hyperlinks so that you could look into these options. That's currently not there. We didn't add it in time for the feature cut for Emacs 31, but I think for Emacs 32 that's going to be an interesting Feature to have at some point.

5:00 finding a balance between "it's fine the way it is" and "just use Doom Emacs"

Philip: And actually the idea had been floating around I think like every time there was like there's a periodic, periodical discussions like how should we make Emacs more user-friendly on Emacs level and people say we have to like say the extremist position is what do you mean not user-friendly. It's perfect the way it is. It's God-given configuration. And the other people who say, well, why don't we just install Doom Emacs and make that the default then? Somewhere in between, I think there is a reasonable position to be had. But in these discussions, one of the reasons this came... I participated maybe in four or five of them, and then this point came up: why don't we have a theme, like a collection of user options, which you can toggle in one switch, which enable all the options from which we would not find, which existing users would not find interesting, which are always the bulk of the users. Most people are already existing users. They don't come in and... One of the things is, lots of existing users, I'm thinking of like a 60-year-old professor who has been using Emacs for 30 years, or a software engineer who's using it, and maybe consciously or unconsciously appreciates the fact that it doesn't change every few years. You don't have a graphic designer. This is, of course, me against graphic designers and UI designers who have a need to reinvent the UI interface every few years and then things change. And how do I save now? What's the... What's the button to do this? And the UI changes.

6:37 people value stability, but also conventions have shifted.

Philip: The people who value the stability. But of course, the common conventions have grown apart. What Emacs does and what people are used to from other programs.

6:50 ways Emacs does things differently: ex: terminal vs eshell, output is editable; new users want to edit the previous prompt; sometimes goes against people's intuitions

Philip: Now, at this point, we also have to distinguish that there are things which Emacs doesn't do the way other programs do, which are... Which I would argue are actually sensible. For example, I think one issue I remember was when I first started using Emacs, I had a terminal emulator. I wanted to have a terminal emulator within Emacs. Nowadays I use Emacs Shell, which to me seems like a more truer Emacs experience. It's an opinion, a strong opinion maybe. And it's also influenced by a history of using Plan 9 and that kind of terminal where actually the output is just as editable. You can just search it. You can edit it. You can cut it. You can interact with the output any way you would use a normal text, which is not something you can do with a terminal for purely historical reasons. At my university, the university where I studied computer science, I frequently helped people in the introductory Linux course. One thing you notice there, these are real newcomers. These are people who have never used Linux or a terminal or anything like that before. The first thing they do when they want to, like, they use the arrow keys expecting or click on, they use the mouse and click on the previous prompt. And they want to modify the previous prompt. Of course, that doesn't work because that's not how terminal emulators work. All the previous output, that's fixed. You don't touch that anymore. Everyone, I guess even people who we describe as newcomers, talking about Emacs, obviously know of course you don't touch the previous prompt in the terminal. These are some expectations you have, if you use Eclipse, if you use VS Code, if you use... I'm not sure how the NeoVim terminal emulator works. I know they have a built-in one. I think Vim also, but I'm guessing right now. So there are some accumulated intuitions which Emacs actually intentionally doesn't want to give, doesn't want to give in all purpose, because I'd argue that one of the strengths of Emacs is really having this uniform text interface where I can use isearch, I can use occur, I can use the highlighting commands, I can just select a region and write it out to a buffer, and stuff like that. That shell buffer is no different than anything else in that respect. Please interrupt me by the way. This is not supposed to be a monologue.

Prot: No, no, no. Go ahead.

Sacha: So it sounds like there's an interesting challenge here.

Philip: Breaking some of these intuitions is legitimate.

Sacha: Yeah.

9:21 How do people develop Emacs intuition? Immersion

Sacha: How do we help people develop the Emacs intuitions?

Philip: To some degree, it really feels like it has to be something that you immerse yourself in. The issue, I guess, is, well, I know, I mean, I knew people who actually used Emacs. I mean, you can help them in a face-to-face setting or like Prot does in his teaching settings. Then you communicate certain things, which I don't want to say they're ineffable. It's not like you couldn't write them down in a manual, but it's also... Like the mentality that people have.

9:55 example: dabbrev, there's no undo? Ah, it's just the regular undo.

Philip: A different example I have, like, I remember I was using daabrev for the first time or something. For a while I was irritated. There was no undo. Like, how do I go back to the previous text expansion? Until at some point I realized, oh wait, it's just regular undo. That's just the way you undo it. But somehow writing this down in a manual is... It's not an easy thing to always think of these things. For me it seems obvious now, but at that point I specifically remember it was unintuitive. I had this accumulated expectation from other programmers if I have a text expansion in this case that I'm actually cycling through some special sort of menu, not thinking of it as just regular text buffer operations. Just text editing in some fancy way. But that's one We should keep in mind. This was all related to the preset theme in some way, right? You're writing this down.

Sacha: Yes, I'm writing this down. That's why we have notes.

11:00 newcomers presets: smooth over the intuition-disrupting things that are not actually necessary/beneficial; ex: enable which-key

Sacha: So what I'm thinking is you wanted the idea behind the newcomers presets is to kind of smooth over some of those intuition disrupting things where people are coming in with maybe expectations of how stuff should work in a modern editor.

Philip: Specifically, the intuition. Specifically, the intuition-disrupting things which are not necessary, in some sense. Like, we wouldn't want to be an intuition disrupt... like you could probably... Like Cua mode or something, that would be something where people if they would start using... If you would enable Cua-mode by default, that would inhibit further development, because then it might be confusing with using C-c, like if you... because suddenly Delay becomes a user input, which is usually not the case with Emacs. I know which-key is an exception in that case, because which-key pausing actually is an action and displays a pop-up buffer. And we do enable which-key due to popular requests and the preset theme. I personally was a bit hesitant about that one, but it seems to be something. where you have to really weigh it on a case-to-case basis. But, Sacha, do you have the... What version of Emacs do you have running there? I can't make it out.

Sacha: Yeah, this is Emacs 31, so I do have...

Philip: So you can open the preset theme, right?

Sacha: Yeah, yeah. Hang on a second. Let me bring up a... I have now a terminal, so I can... Let me bring up a completely fresh Emacs.

Philip: No, I just want you to open the file. Because in the file there is a prelude. There's a commentary section that actually explains the curve. It's not a library. That's exactly the joke with the...

Prot: Yeah, that's part of the problem with those themes.

Philip: That's the problem. Themes are not libraries.

Prot: It would be easier if they were all there. It's a kind of an implementation detail that from a user, it doesn't really make a difference.

Sacha: All right, newcomers-presets.

Philip: If I remember correctly...

Prot: Yeah, yeah, exactly.

Philip: Yeah, and you see up there the commentary section?

Sacha: Yeah.

Philip: If you scroll up a bit, it's above line 37. The theme configures which we can reasonably expect the average user to want to enable, but would otherwise be unlikely to discover on their own. That's sort of the overall guide of what options we want to add. That's why it's also an option on the splash screen. You just tick it, and then the user options enabled in the theme should be activated by default. That's sort of the idea.

Sacha: It is available on the splash screen. So if I say display-splash... Oh my goodness, how do I get to the splash screen?

Prot: It's C-h C-a or not? I forgot. C-h a maybe?

Philip: There are two things. There's a splash screen and there's the...

Sacha: Hang on a second. I'm just going to start a new Emacs.

Prot: Yeah, I haven't done that in, like, I don't know...

Philip: That's the about Emacs screen. But you have a display splash screen.

Prot: C-h C-a on mine. About Emacs. M-x about-emacs.

Sacha: No, I have a better idea. I'm going to start this new Emacs person. Okay, here we go. New Emacs. Fresh person.

image from video 00:14:32.733Sacha: So we click on this, right? And it turns on a bunch of things including the tab bar.

14:32 newcomers-presets choice is not saved at the moment

Sacha: I wasn't entirely sure how people would save that so that it happens again next time. Is the idea that they just keep checking that box?

Philip: That's not done currently. That's something we haven't simply decided on. The current presentation is you enable it in that mode and then you'd have to, which is of course saying it out loud makes it sound stupid, but you'd have to persistently save the themes. So then I think it's optional to save themes and then...

image from video 00:15:14.000Sacha: It is possible for people to get to it if we leave them a breadcrumb. But it's not going to occur to them because it would never occur to them to say customize Emacs, custom themes, and then I can pick newcomers themes from here.

Philip: It's a point that I at least intended to mention at some point on emacs-devel, whether we want to make this, because currently it just loads the theme, but it doesn't persist the choice, but it could just as well persist the choice. There's a discussion to be had which of these two behaviors is more intuitive, because of course, if you persist the option, then you have the disadvantage that someone might enable it, but doesn't actually want it, but now somehow their Emacs is broken from their perspective. I don't want tabs or whatever they say, or I don't want which-key, and they don't know how to disable it. So this is... I wouldn't say it's an obvious decision in either direction.

Prot: Like if there is an enable button or save, there should be a disable and unsave, like remove.

Philip: Yeah, that's the checkbox idea in that case.

Prot: That would be the tricky part. And especially, finding the place on the splash screen so that this actually works for everyone... Because if you open it in a TUI mode, I think then initially, if I remember correctly, we had this button or this new to Emacs line was underneath the copyrights. No, no, that was a different thing.

image from video 00:16:46.233Prot: If you click on newcomers preset, for example, then you are redirected to the manual entry. And I think we had some, yeah, there's this, the top line. If you got here by clicking the link on the splash screen, that was on the bottom. That was on the bottom of the manual entry. But if you open it up in an 80x24 terminal, you wouldn't see this line.

Sacha: You can't see it and you don't know how to... These are the complications that you have to keep in mind in that case.

Philip: You might not have the intuition that SPC is scroll, which I think that's the case in less. But yes, again, you have this accumulated intuition from using Unix tools. Which is one of the points I wanted to bring up.

17:08 newcomers without much computing experience might even find it easier (no C-c expectations, C-v etc)

Philip: Who is this mythical newcomer? What's their actual background? Because I claim, and this might be controversial, that if someone's actually new to using computers at all, which is something I have seen, like people who have never programmed, people who have never used Unix, people who have never used more than a web browser, to exaggerate, they appear to do fine with Emacs because they have no expectation of using C-c, C-v, C-c, and so on. They know that they have to use the buttons up there. So in that sense, they're fine. There's an optimization loop when you're used to these shortcuts and a few of these conventions how to move around, that Emacs defaults appear to be inconvenient. So that's also a distinction you have to make in that setting.

Prot: Exactly, exactly. Plus you cannot optimize for everybody. Eventually you just have to make some assumptions.

Philip: Exactly. But what these assumptions are is the controversial...

Prot: I think the way you approached it makes sense. This is the reasonable way, I think, to do it. You have to assume that they have this background knowledge. And if they don't, it's what you said. They don't have to relearn something because they didn't know it to begin with. So they start from a good basis.

18:30 Focus group?

Sacha: Is there interest in having some kind of focus group or something like that so that if we come across newbies, we can say, hey, you know, the developers would like to be able to float some questions once in a while to see what actual newbies would think of this?

Philip: I have actually tried this once. I was in a hacker... what's it called? There's this computer club in Germany and they have local events on a regular basis and I was going to one anyway because a few friends of mine were going there and then I did an introduction to Emacs course there and printed out a survey basically, a questionnaire for Emacs neophytes. I think if you search for that string on the Emacs development list, you're going to find that. And I gave a few people these texts. I printed it out. It was actually pieces of paper, so it wouldn't be personally identified. There wouldn't be any information there. And one of the things I thought was interesting in the results was that the main thing people were saying was it's overwhelming. Like the amount of things... Just the default Emacs. No configuration, no options, no auto-completion, no fido, whatever. It was just so many new things, so many differences that they lost an overview, basically. This was a group of people who, I think there were questions, and they were like, how long have you been using computers? Because, of course, it was so generic. What previous UIs have you had experience with? Most people use Eclipse or Vi, NeoVim and even reasonably complex Vim configurations. Of course, this is a bias due to the setting in which I was asking these questions. I'm actually planning to repeat this experiment because I'm going to another one of these congresses or these meetups in a month or so. I wanted to offer this again to people, specifically seeing if these newcomer presets are valuable or if they help people or not. But of course, doing this in a properly scientific setting would be much more difficult. Yeah, of course. We need money. Difficult steps of doing this.

Sacha: Maybe even like a mailing list. We can say, hey, you know, you're new to Emacs, but you kind of want to make it better. Email this person. And every so often when developers have a question, they can say like, does this make sense to you? Here's a screenshot. Or would you prefer this versus this?

Philip: As in, we would send an email to all the people, but then I think, I mean, the big question, difficulty in that sense is then data protection, I think. That's what I was trying to avoid with having this just printed out and no personal identification, because then we have to store email addresses.

Sacha: Okay, all right. That's fine. That's fair.

Philip: So, sounds like an excuse. Partially it is, but something like, I mean... I'm not saying that my approach, what I was doing was unbiased. There are people who would be more willing to answer these things and people who are less willing. I know the bias in this case because I actually saw the people and I had a feeling for what kind of people they were. So I think I'm in a better position to factor it out. But if it's actually properly, if you just have people who you send emails to

22:15 Emacs survey before

Philip: I'm not sure if it remains represented because there have been these Emacs surveys in the past. I remember at least two generations. And they're of course the ones which are circulated on Reddit, on Hacker News, on IRC, which I still think is a bubble of maybe 200 people. Like mainly 200 people and some people who are Surrounding these groups. So I'm always sort of dubious because these are the people.

22:48 people's backgrounds influence their responses

Philip: I mean, these are people who are much more likely to have heard of, what's it called, Evil Mode or something like that, or had some experience with other editors. And these things all influence their responses. always taints the results. Every time these discussions are brought up on Emacs devel, people have some level of doubts as to how reliable the results are.

Prot: Correct, correct. It's hard to get reliable results, though some data is still better than nothing. But granted, you don't want to base decisions on those results, of course not.

Philip: Yeah, that shouldn't be the last decision-making factor. You should just have a function where the input is whatever the data is, and then the output is mechanically determined by that. Yes?

23:46 Hypothetical: Reset themes, to reset things back to the defaults of a specific Emacs version

Philip: Now, related to the preset theme, there's also been a discussion (I don't think this has been mentioned much online) of so-called reset themes. I'm not sure if you've heard of these. So the idea would be, additionally to having preset themes of options, which we have changed, which we would recommend because the newcomer preset theme makes no real assumption that the options will be stable, so we might change them from version to version, this gives us some flexibility to say we have a new option. Like, for example, if the preset theme had existed since Emacs 29, and now in Emacs...

24:22 package-autosuggest-mode suggests based on file extension

Philip: That was actually the reason this entire discussion started when Emacs 31, that's the current release... to be released, there's this package-autosuggest-mode so that's a little prompt, when it's enabled, a little prompt in the mode line. You can click on it, Emacs installs the package which it believes to be the right one for the current file.

Prot: The major mode, right?

Philip: No, it's a minor mode. It's a global minor mode.

Prot: No, no, I mean, but it installs based on the major mode, right?

Philip: Ah, yes, yes, yes. It installs a major mode package, which matches the current file format being used based on auto-mode-alist or the magic, what's it called, magic file alist and all these things, and it can... We didn't want to enable this by default, but we wanted to enable it for newcomers. That was actually the first option in the newcomers preset. If the preset had been older, we would have still wanted to add this to the preset theme. It's not supposed to be set in stone. Now the idea with the reset theme is, and this is still hypothetical since we haven't implemented it, is to have reset themes for specific Emacs versions. So we, in Emacs 32, we might have an Emacs 31 reset theme for all the options that we have changed in Emacs 31, in Emacs 32, so that we could reset them to the previous option. So that in this sense too, if the discussion, if the question is really just, we don't want to annoy people who have... When upgrading, of course, it's still a minor inconvenience because they have to write load-theme emacs31-reset in their configuration, but it would be easier for them to actually undo any changes. And in future versions of Emacs, hopefully also persist these changes so that you can really sort of like pinning your version of Emacs, a soft pinning of options. So this is something for the future. Consider as well, which would be reusing the theme approach, which is another reason why I hope that the notion of user option themes will become more, because it's been there from the beginning. The Customize system has always supported user options to be added, but people have always only customized, not only... I'm not sure no one has ever done it, but it has not been a popular approach to use the user options, even though the technical facilities have been there all the time. That's also going to be interesting if the reset theme would be forwards compatible. But that's another discussion that makes it even more complicated. So that you could add them hypothetically to ELPA as a core package.

Prot: Nice. Yeah. Of course, the reset themes, if you implement them, that's great because it opens up the possibility to be a little bit more ambitious with the defaults and break.

Philip: Yeah. Because that's exactly... Every core... Every default discussion boils down to: if we break this, people won't understand what changed. If we change this, people won't understand what broke. But on the other side, people like all new... Can we reasonably assume that all new people would actually want this theme? Then we want to give us some sort of more flexibility in this sense without actually the support, because I think that the value proposition of having a stable interface where you can expect the appearance of the theme to be somewhat stable over time, how Emacs behaves, that's actually a positive thing.

27:52 Emacs 32: bundled versions of Emacs (Big Emacs - distributions that include more packages)

Philip: And finally, in Emacs 32, this is also a finally. For now, one thing I just thought of, which I was reminded of, there's a big plan for Emacs 31. This is one of, I've never pronounced his name, Sean Whitton, I think it should be pronounced. He said that one of his plans as a maintainer will be to work on the bundled version of Emacs, which some people, including myself, have been calling Fat Emacs. So adding, selecting certain packages from ELPA, from GNU ELPA, and bundle a secondary distribution of Emacs which would include additional packages, Which are currently, so for example, one example would be org-tex. And then you could, when you install Emacs, you could install, I don't know, big or fat or whatever... Big Emacs with all these packages pre-installed, which would be pinned to the right version which we would have hopefully ensured that they're actually compatible with one another. And then you have the normal Emacs, which would be the thinner one. And an interesting corollary of all of this would also be that if the way from ELPA into the core would be made easier, that the way out of the core into ELPA would also be made easier. Because that would mean it's more easier to deprecate packages over time since you can install it. This protective layer, let's say, protective layer, protected merely by inconvenience and the annoyance of moving these packages in and out, would fade away over time. Some cruft within Emacs itself, within core Emacs, could be moved to ELPA. So we could actually thin down Emacs. That's one possibility. Oh, that's big. Yeah. One strand of commentary in that direction. That's something that I'm planning to help in the Emacs 32 development cycle. Because these options then could also be in... Any options related to this could also be added to the newcomers preset theme.

29:54 Selection versus multiple completion

Philip: So one could of course... Vertico or these interactive selection packages... I think I've commented that before there is a certain controversy there. I think that there's a certain controversy that selection is not always the same as text expansion, which is sometimes like... There are, I think, the certain... skeleton, or there's this insert... what's it called, auto-insert command... It's not auto-insert, something like that, that prompts the user for multiple things, but it's not written using [completing-read-multiple], but it's written in a way that there's a manual loop, which waits for an empty input to occur. But if you're using vertico or fido, by default, if you just press RET, you don't actually have an empty input. You just select the default option. There's settings like these which where these sort of these two kinds of completion diverge from one another which which is also something I've been talking about for a few years but never came around to implementing that there should be an API distinction between actually selecting user options from a list and the completion interface which we have for files or commands currently. These are semantically two different things, which would be interesting to see if it would be worth distinguishing the two in a technical sense, because that would mean that in certain settings, we could enable Fido. I totally admit that Fido and Vertico have their advantages when it comes to discoverability over standard text completion. The compromise now was that in Emacs 31 there's this option, I think it's eager completion updating or something. It's a combination, it's a permutation of these words in some sense. So that's if the completions buffer pops up. No, you don't have to... It doesn't matter. You don't have to visualize it. Yeah, where they update as you type. Updates as you type, yeah. But that doesn't occur down there, but it only occurs in the completions buffer. That's sort of a compromise. That's Fido, right?

Prot: But the generic completions has had a lot of improvements over the last few years. And in Emacs 31, it's in a very good state, all things considered.

Philip: Which was also partially driven by your MCT package?

Prot: MCT, yeah. Which was an experiment, of course. But yeah, it's basically that idea. Because I have used this in earnest, like the default like this, I have used it for a long time in earnest, like just defaults. It's very good. It's for sure very good. Whereas Fido and Vertico are better if you are just getting started and you don't know that there is a completion on the mini buffer and somehow there is a distinction between the two. Like, for somebody who is getting started especially, I think this interface is not good. But if you know what you are doing, I think this interface actually works perfectly. And it has a lot of options. So, Sacha, what you are showing there is the absolute default, but it has so many options that you can make it look actually quite different from this and very similar to Vertico, for example, in terms of the user experience. I just realized that...

Sacha: Oh, I just realized that if you do the TAB TAB, if you do the TAB TAB, it now goes to that one, which is great, but you can't filter it from there. You can't type into it and have stuff happen.

Philip: Yeah, it's not down there. If you're down there in the mini-buffer, you type. There you have just a regular text buffer, so you can search or you can select stuff out of there.

Prot: And that's also an option, by the way. So what happens on the second tab, for example, so you can configure that.

Sacha: Right, so that was the second tab behavior from newcomer-presets.

Philip: That's the option I proposed and then objected to.

Sacha: Yes, work in progress. So basically, you have these newcomers. We're trying to figure out how to get them through their learning journey. The newcomer presets can smooth over some of the edges. It can get over that "Yes, there are a lot of options, but at least M-x with tab completion will show you the things so that you don't have to memorize the names as much." You can recognize them from the list. You can narrow it down.

Philip: The behavior is supposed to actually be similar to Bash, the way Bash does completion.

34:39 Manuals

Sacha: It's probably still... we're going to need them to read the tutorial, and we're going to need them to use a lot of patience as they get used to Emacs. I am not quite sure yet if we can get them all the way to, all right, here's how you open your config file and define your own keyboard shortcuts, for example. Bit of a journey.

35:08 More examples?

Prot: I think that one way to do that is to have more examples in the manual. Like, here is how you do this, here is how you do that.

Philip: Or there's this other manual, the Emacs FAQ.

Prot: I don't mind where it would be, like FAQ is totally fine. I don't mind exactly where it would be, but somewhere in the documentation, like common patterns of Emacs configuration kind of thing. Maybe it already exists, so if it exists, then of course even better.

Philip: Emacs FAQ has some things on finding related packages, common requsts, bug reports, but maybe it was... I remember there's something. If I link to it...

Prot: Where is the FAQ?

Philip: It's a separate manual.

Sacha: We do not have it from here, not from the splash screen, but it is available from the Help menu.

Philip: I think it's not been that thoroughly maintained.

36:22 find-user-init-file?

Sacha: I'm going to take advantage of the fact that you've actually been reading emacs-devel. Has there already been a long discussion about whether a M-x visit-user-init-file makes sense? An interactive command that you can use to open... I was trying to find it, but even with Yhetil's search, I was like, okay, there are four threads. One of them was a long time ago, and the other one was from even longer than that, so I didn't know whether it was some other discussion.

Philip: I don't recall any such discussion recently, but I also don't think that anybody Objection to it. So it's really just a matter of someone writing it down and adding the documentation.

Sacha: I would like to do that.

Philip: It would be quite likely 24 hours.

Sacha: Okay.

Philip: On the master branch and not Emacs 31 branch, which would be slightly... It's fine. Yeah, but even having a button...

Sacha: If it makes it in someday, it doesn't have to be in the splash screen. It just has to start off being available through... And then we don't have to keep telling people, oh yeah, do a describe-variable on the init file just in case your init file is actually .emacs instead of the .emacs.d/init.el that other people are telling you to use instead. It's a bit of a mess, right?

Philip: I think some people have been recommending doing M-: and then calling the [find-file] function with the user init... What's the name of the variable again?

Sacha: user-init-file.

Prot: User Emacs file.

Sacha: Here we go. user-init-file. Here we go. That's the thing. Yeah, exactly.

Philip: And if you do M-: (find-file user-init-file), then it would basically do the same thing. That's why I'm saying it's such a minor function that I don't expect any objections.

Sacha: Okay, okay. So I'm going to suggest that to Emacs Devel at some point.

Philip: I've had the same idea many times myself, but the transience of memory has thrown its way before I actually ended up doing it.

38:38 Getting over the reverence for Emacs's history

Sacha: Sometimes I am reluctant to suggest things because I figure Emacs is such a long history. Probably someone has thought of this already, and it's probably been discussed and bike-shedded. But I think there are little things that we can do.

Philip: Yeah, but then in that case, Yeah, but I think that's actually related to another thing I wanted to talk about. There's a certain sort of reverence that people have for Emacs, because it's such a historical project. But I mean, the preset theme was something that was discussed for many times, and there were basically no objections. No one said, no, we shouldn't do this, this is a bad idea. I hope it's not only because I proposed it or something, or like the package also suggests that. Most of the things I've been working on for Emacs 31, no one objected to. And there's two sides to this. There's some people who actually go overboard with this and try and reinvent. Like when reviewing packages, you see this a lot of people try and reinvent functionality, which is basically just giving a new name Combining two things and giving it a new name which isn't always necessary but might be useful and then it's some discussion like can we actually make more out of this and that's a different thing but then there's the people who I probably lean more towards that side when I think to myself the way I'm doing this is stupid or this is not as efficient people have been using Emacs for 40 years of course there probably has to be a better way to do this

40:11 Changes are more likely to happen when someone puts in the work to make a patch

Philip: And sometimes it turns out it simply hasn't been implemented and no one has simply done this actually small effort of preparing a patch and ironing out the details just some people don't like discussions of course and it's understandable but you can I mean there's really no harm in sending a patch and then saying I'm sorry I don't have It's annoying, of course, from a maintainer's perspective. I don't recommend doing it, because if you prepare a patch but don't have the time to finish it up, then if it's a useful thing and you actually get someone to be interested in maintaining it, then bringing the patch to completion, then it's well worth just sending a feature. Even sending a feature request, you don't even have to... I mentioned the idea of this preset theme many times. I wish people would be more conscious of this mentality, but I totally understand people who think otherwise, because when the first time I sent a patch to a mailing list, I was, I don't want to say I was sweaty, but I was really nervous because I don't know what if they insult me or they say, "you fool, you didn't format the test properly, [??] secret handshake you have to do every time you send a patch. Begone." Whatever. Which is of course not the case. Which is not to say that there are no unpleasant people on mailing lists but I think that there is especially the GNU Kind Communication Guidelines, which are supposed to give some sort of goodwill, good faith, attention to how people should behave on mailing lists, how they should treat each other. Lots of these preconceptions turn out to be false in there. That's why I also wanted to participate in this, so that people see, oh, the people maintaining Emacs aren't wizards locked up in a tower, but just, I hope, normal people who happen to spend more time with Emacs.

Prot: Yeah, that's a very good point.

Philip: Which is why they're valuable, these discussions.

Prot: And I think, Philip, just to add to this, your example of leading with a patch, I think, is also key here for someone who can write a patch, of course, because it cuts out a lot of that noise, that initial discussion of, well, maybe yes, maybe no, because it frames minds. It focuses the attention on something concrete. And that can also... Yeah.

Philip: Yeah. And... I mean, having a patch is useful, but getting someone interested is also helpful. Like the discussion when we merged which-key, I helped with that process. And I'm not, I think it was, I don't remember his last name, Jeremy, who actually did most of the work. And I was reviewing his patches. I was helping along, but I wasn't actually writing most of the code. I was just going over the proposals and helping along and basically pushing the... Stunning the process whenever it got stuck so that we actually made the necessary changes for it to get merged.

44:03 Preserving Git history of packages absorbed into the core

Philip: And then I did the last finishing touches of merging, because that was also something... Every time... We'd like to preserve the Git history of packages we merge upstream, which is probably something we won't be doing in that way when we do the Fat Emacs releases. But the entire history of Eglot and the entire history of which-key is actually preserved in the Emacs Git repository. So if you open the file, you have, it's not anymore a tree in a computer science sense, but it's actually a proper DAG, because suddenly you have multiple roots of the project which come together with the history preserved. And that's an annoying thing to do with Git, but you can do it. And not everyone knows how to do it, but a few people have the commands written down somewhere or look it up on a mailing list, as I do. Then that goes through, but that's...

Prot: So they are wizards after all.

Philip: Wizards just reading pre-written down spells.

Sacha: It'll be interesting to see if some of the starter kits move to using that kind of fat Emacs infrastructure once that's in place. Because a lot of times the starter kits are there to package together. Okay, here's a list of the packages that it uses. Here's the configuration that makes them play nice together. And then here's some kind of Documentation or videos or a demonstration on how to use it to help people get started.

Philip: So I'm curious to see, I mean, I went reviewing the options to add to the preset theme. I actually went through a number of these starter kits to see the options they suggested. Selected those out which seemed reasonable to me. And of course, this was discussed and people objected or added other things. But I am curious to see how the starter kits will evolve in the future, because that's also something we should mention.

46:00 Dealing with multiple types of Emacs

Philip: I mean, there is a big problem with the fat Emacs approach and suddenly you have two versions of Emacs. You can write a package which appears to work fine in fat Emacs, but it depends on a package which is not in the core Emacs release, and then that's something we will have to deal with in the future as well. Yeah, that's a tricky part indeed. Yeah, but another thing relating... Yeah, the sort of fragmentation of what core Emacs is. It might be a showstopper, so maybe everything I'm telling here is just a wishlist. It doesn't end up actualizing. And that fragmentation of the setup is one of the things... Because it's not actually really difficult to solve. I mean, if you have a package that depends on something from Fat Emacs who just added to the package requires lines, you explicitly state the dependency. But if people are sloppy, then they might not notice this immediately. And you have runtime issues when people are slow.

Sacha: It's a little bit more than that, right? So for example, if you have a newbie asking a question, because they're using a starter kit or in the future, a fat Emacs thing with different packages installed and different configuration things that they have not personally set up. And they don't have the experience to know, oh yeah, this is going to be related to that. So I should mention it in the help message. I mean, large starter communities like, like Doom Emacs and Spacemacs will have their own Discord or mailing list where people can go and ask for help. And so people will say, okay, I think I kind of know which starting point you're coming from because it's the base. But if we're, you know, with the smaller starter kits, they don't even know how to ask for help. And everyone is like, on the regular Emacs communities, there's a lot of back and forth if you want to dig into, okay, what do you have enabled? What is affecting your setup? Fat Emacs is going to run into that problem.

48:09 Fat Emacs is just about bundling more packages from ELPA, not changing the configuration for them

Philip: To be fair, my understanding currently is that it wouldn't enable any other options. It would just bundle more packages.

Sacha: I see.

Prot: So it would be more of an issue for package authors.

Philip: Yeah, for package options. The idea is, I mean, I've used Emacs in offline settings where it's like, really inconvenient or impossible to install additional packages, and just having more functionality out of the box which ELPA provides and you don't have to install additionally, is basically the idea. Because this has been a project which has been ongoing for years. I think this is ever since the conception of ELPA itself, which is precisely the reason why GNU ELPA requires all packages to be signed or to be covered by the copyright assignments, while NonGNU ELPA does not: so that this is possible. It's just that finally it looks like we're starting to move somewhere in that direction. It would be interesting if a decision were to be made that we're going to give up on this sort of bundling, what decisions that were made for the legal status of GNU ELPA, if we would merge GNU ELPA and NonGNU ELPA together, which is unlikely currently. This is just pure speculation at this point, but it's something that might be a discussion, which will be had in the future.

Sacha: Okay, so it dispenses with a package install part, and so people don't have to worry about, okay, how do I make sure The package archives are set up, and how do I install the packages? All that stuff will be pre-installed. The auto-mode-alist will be... Oh, sorry, go ahead.

Philip: The package archives wouldn't matter that much, since we are just talking about the GNU ELPA packages, which are installed by default. It's really just that you don't have to install additional packages. You don't need a network connection. You don't need to know about the package existence. It would be registered in the auto-mode-alist anyway. So if you open a, I don't know, what's the package, some major mode that's not going to open, which is not in the core.

Prot: I think you might [??] earlier. I think that would qualify. I think you mentioned auctex earlier, which is on ELPA, but not in Core.

Philip: The tricky thing there is that Emacs already has a LaTeX mode by default, and that already applies, but auctex extends it. That's why I was looking for another example. Okay, that's the idea, but it wouldn't only be major modes, I assume. There's going to be some discussion as to what packages we want to add. Currently, it's not certain. Because we're working on finishing up Emacs 31. That's where most of the bug fixing efforts are going in right now before we progress to any further developments. But that also includes proposals. That includes proposals as to the preset theme, which I am still interested in reading.

51:23 Customize

Sacha: I want to come back to something Prot mentioned in my conversation with him about newcomers, and that is the Customize interface versus getting people to the Emacs Lisp directly. And I think, Prot, you were not very keen on Customize.

Prot: Yeah, basically if I say it in one sentence is: I think the earlier they get into Emacs Lisp, like seeing it and interacting with it, the better it is for them long term. Granted, I am making the assumption that this is a user that will be there long term, right?

Philip: Of course. And this is specifically about the Customize UI, right?

Prot: Yeah, yeah, not the underlying functionality, like, yeah.

Sacha: It's great for simple options like, yes, we can check the checkbox, or we can select from the drop-down list or whatever, but browsing it is, as you mentioned, overwhelming in the general sense of Emacs being overwhelming, and when you start wanting to do something slightly more sophisticated like you know, let's add some more capture templates, then it's challenging for people to do. So I'm wondering whether, in general, we should be... Is our general strategy to be guiding people to, yes, Customize is there, but really you want to be doing Emacs Lisp as quickly as possible. Let's make it easier for you to get your init file. Let's make it easier for you to test your init file and not fall apart when you miss a parenthesis and all, things like that. Do we want to guide people that way?

Philip: One question I think we should distinguish is the idea of a UI the problem or is it really... Because I personally I have a new Emacs configuration at my day job, and I do everything using Customize. I don't even care about using use-package or whatever. Just customize the stuff using... There's a big blob of user options which I've modified, and that goes through, and I don't care about it, but I claim to have some understanding of what's going on, and the rest of the function is just some defuns which I find convenient. But for me, it's okay, because I have some sort of intuition of how the Customize UI works. If there were a better UI for Customize, would you still say that if it were written in an intuitive way, say using Fido modes. So that's, it would use interactive narrowing and it would somehow work in a build on existing intuitions because the current Customize, the Customize UI, the easy customization interface I think is a technical term to use is based around this widget library interface and sort of make replicating a TUI menu but not... And then you have to... And yeah, of course, the intuition... Like, if you click on things, it doesn't always behave the same thing you would expect from a regular settings menu, which is by the way also something that CUA specifies.

54:41 CUA - Common User Access

Philip: I recently looked into what CUA lists. Like, if you look at the Wikipedia page, CUA specifies that every application has to have these settings menu with tabs on the bottom on the top where it lists all the options you can specify and interestingly C-c and C-v is not listed as...

55:00 ini file format? https://sdf.org/~pkal//blog/emacs/ini-init.html

Philip: Apparently not CUA, but Shift Insert and Control Insert... I might be misunderstanding this, but this seems to be a misnomer.

55:10 Emacs configuration generator

image from video 00:55:45.367Philip: But if we had some sort of a UI like this CUA configuration UI, would that be something where you'd say as an intermediate stage for just setting options? Because that was part of my thought process with Emacs Configuration Generator. Just configuring Emacs is such a subset of Lisp as it's actually not programming Lisp. You can easily get by by just using add-hook, set up or setq, and add to list or stuff like that. But you don't really have to understand. It's just a peculiar syntax for how to program Lisp.

55:54 INI-style configuration

Philip: I'm not sure if either of you have seen, I wrote a blog post last March, no, not March, what's the name of the month? November, October or something, where I gave a prototype for a INI-like configuration syntax.

Prot: I must have read it, but I don't remember it. You must have read it. Yeah, yeah, yeah, because I always read my feeds, but now it doesn't ring a bell.

Philip: Exactly. You see there's this basically a simplified syntax, which should be... The idea was it should follow a conventional configuration-like format, and each of these lines gets translated directly to an Emacs Lisp expression. And due to this, I don't want to call it an isomorphism, but the easy translation in both directions, I think that the expectation of saying write Emacs Lisp... There has to be some defun or something if you're writing Emacs Lisp. That's to exaggerate. If you're just writing setq, set, add-hook, add-to-list, these common configuration patterns, which are well worth documenting in the manual, to understand what are the patterns that you have to use to configure a package, even understanding the signature... The distinction between add-to-list and add-hook is that hooks are lists which can have mode-local extensions but also inherit from global settings. Not obvious from the beginning to everyone. This is not list programming.

Prot: Yeah, fair enough. Though even then, they start to see the parentheses, get used to the syntax. They have to remember to quote stuff. Even though it's not really programming, I see what you're saying. They put themselves in the situation.

Philip: One of the ideas precisely in the config syntax is that if you have an option like set, you see the first line, set mode line compact long. Long is a symbol. I just use regular read to read this, and it's not evaluated. There's an option down there somewhere, I think, eval set, where the format expression is an S expression that's evaluated to a string. So you have to opt into evaluation. which seems more intuitive to me for a regular configuration when you're writing it, because all these things... Like, I have to think about quoting. Then there's the issue like with with-eval-after-load... Can I customize this variable before the package is loaded, after the package is loaded? If it has, like... If you're adding something to a list and the list has a default value that you don't want to set the value of the default, don't want to add it to the list because then it's not loaded, and it could trigger a undefined variable signal. So these are other inconveniences that I don't, I personally do not see any value in teaching people or having people to deal with these sorts of issues before they have any broader intuition. Which is a very idiosyncratic take perhaps, but...

Prot: No, no, it's fair.

Philip: What I'm trying to get at is this sort of any configuration syntax would be something that a UI could generate a lot easier and in a way that wouldn't have this artificial split between your own personal handcrafted configuration and the generated part of the configuration. Mechanically changing this, finding the section package avy, because it has all of these primitives which didn't exist early on in Emacs, like packages and features exist and so on. The sort of structure which use-package usually provides.

Sacha: I have about one minute before the kiddo starts on lunch break, so I'm going to interrupt a little bit and do a quick summary. But the two of you are welcome to keep hanging out and chatting. I'll leave the Big Blue Button room open. And if you want, I can set it up so people can join you, depending on your time, et cetera, et cetera.

1:00:21 Quick summary

Sacha: But basically, what I'm getting for a quick summary of the conversation: Emacs 31: the newcomer presets is work in progress. People are definitely open to improvements, ideas, other suggestions for other features. The kiddo is just running out now. I will put the chat in the thing.

Prot: Yeah, of course, of course. That's fun. So, what's happened?

Sacha: Do you want me to open up the chat to everybody? Or do you have other things?

Prot: Me, I can stay for another 20 minutes. Just to say I can stay for another 20 minutes because then I have to take the dog.

Sacha: Yeah, and Phil? Oh, you have to leave.

Philip: 20 minutes is fine. 20 minutes is fine for me as well.

Sacha: Okay, okay. I will put the thing in the chat and people can continue because the kiddo was like, ah! Okay, yes.

Prot: Okay, okay, okay. Good. So, yeah, of course, there is a chat going. Yeah, let's see. So, Sacha, you will link it there. Ah, nice.

Philip: So, I presume there has been an idea of people watching this.

Prot: So this is live.

Sacha: And I can copy the chat thus far since we didn't even get to any other questions. Hang on a second. Where am I even?

Prot: We're trying to deal with those, right? Yeah, yeah, yeah. Well, eventually to have a discussion and also take questions, eventually you need to have more time, I guess.

Sacha: Yeah, yeah. But thank you all so much.

Prot: Yeah, yeah, yeah. That's good. Yeah, yeah. Thank you, Sacha. Thank you very much. And of course, the kiddo overrides all.

1:02:27 Continuing with INI

Prot: That thing with the INI, I think it's very promising. I mean, if you flesh that out. Because the other thing is, yeah, with the INI configuration, because what would be, though, the fate of what is now added, you know, when you modify something and it adds this, you know, this has been set by Custom, do not touch it kind of thing. You know what I'm talking about, right?

Philip: Yeah, you mean the generated user glob. Well, my idea, or if I were, if I had the time /motivation/whatever to flesh this out, because currently it works... Currently it's an actually existing Elisp file which you could use, but I think it would be most interesting if it would be upstreamed. It would sort of be like, if you don't have a .el file, Emacs would look for it .ini file, or emacs.ini file or something like that. Then, of course, you can check, like, does the INI file exist or does the .el file exist? Probably there would be a user option to select into which it would inject the new options. And by default, it would select, for example, if the INI file exists, then it would use the INI file. But there is some controversy to this, because I totally understand the sentiment we're coming from with... You're using Emacs, so you have to learn Lisp. But for me, the bar is a bit higher than just the inconvenience of writing out this more or less. It's, as Joel Sussman referred to it, this ritualistic Lisp. You always have to repeat the same stuff all over again, like with eval, afterload, set. add-to-list, then you have to quote the option in one case. And if you change something in a map, then you don't have to add it. And of course, if you know Lisp, then you know that in one case, a keymap is a cons cell, so you're actually modifying the rest of the cons cell. That's why you don't need to quote it. But in the other case, you're accessing it via symbols, so you need to quote it. But this is all technical details. There's no necessity in it. It doesn't have to be that way.

Prot: Yeah, yeah, yeah, that's fair, that's fair, of course.

1:04:42 Motivation

Philip: One thing I wanted to bring up in the discussion when we were talking about reverence was there is, I mean, one part of the thing that gave me the motivation to go through with learning Emacs, even though I didn't use the tutorial initially, was sort of a reputation I heard about Emacs. And the videos I saw, wow, you can do these cool things. And this motivation, this image I had of Emacs help me go through, but if you overshoot this approach, then people expect too much in the beginning and are disappointed in the end and don't pull through. There's this question of having, how's it called, the ??... How to motivate people enough to be interested in Emacs, to actually learn it, but not to oversell it. If you give some sort of a demo of using Emacs, which is simply not representative of how it actually works, then that's something which would backfire. But I guess we can take a look at the questions, right? Yeah, let's see. Let's see.

Prot: Yeah, yeah, yeah. So yeah, I didn't read them. I had the chat open, but I didn't have the time to read them. Sorry? I'm not sure how to parse these. Is this from top to bottom? I guess from top to bottom is how they arrived in the chat. The top is the earliest.

Philip: The usernames are mentioned below.

Prot: I guess that's a copy-paste thing. Yeah, yeah, yeah. So there are some...

Sacha: I gave the kiddo some packed lunch, so I'm back.

Prot: Oh, hello there!

Philip: We were just wondering about how to read the comments you posted. Maybe you have a better UI.

Sacha: I pasted them into the chat. So in the Big Blue Button...

Philip: But that's the order of occurrence?

Sacha: That's order of occurrence. It's totally not very... It's just like a big paste.

1:06:50 Politics and philosophy

Prot: While you read it, let me... Yeah, there is a comment there from LC2000 about the splash screen having a lot of emphasis on the legal side, which is a fair comment. I think the legal side is important though, because of course, free software and all that, but of course, it could be rearranged. So maybe you don't want to have it at the top front and center, you want to have it further down. Maybe. I don't know. I don't have a strong opinion, but I think the legal side is it should be there at some point. I feel like it's a political minefield though.

Sacha: Just leave that alone. Otherwise: 200 comments on emacs-devel, one of those really long threads.

Philip: I cannot under-emphasize how surprised I was when my suggestion to add a checkbox on the splash screen just went through. Because I expected people to object, no, we can't add it there because of some system. It wouldn't look the way it should look and that would be confusing or whatever. But apparently change is possible. You have to be careful and be patient.

Prot: And I guess here there is an assumption, right? There is also an assumption that people will attack you or be unreasonable. And I think this is not true. You mentioned it earlier as well. Eventually you have to get on the mailing list because people, if they don't hear the opinion, the counterpoint, they will never know what to do with it.

Philip: But it's not entirely unreasonable because there are discussions that can be... There are people on emacs-devel, it's sad to admit it, but there are people who voice strong opinions, like strong opinions, with no power behind them, which can scare people away because there's no... There are no tags. There's no index of people on emacs-devel, so you don't know if some John Doe responding to your message, if he's actually responsible for this and makes a decision, or if it's if Eli is sending a message and his decision on the discussion actually weighs a lot more than other matters.

1:09:23 Experimenting with things outside core

Sacha: I feel like sometimes experimenting with newbie-focused resources, like the unofficial ones that are around... At least we can try the ideas out and then say, hey, here's the patch and also here's what people have been using it for, so you can see it a bit more concretely, than dropping an idea into the discussion and then having the whole bike-shedding happening without as much data.

Philip: That's seriously my main recommendation. If you want to propose something, add a prototype, add a patch, add something to narrow down the discussion. That's something people would take away from this discussion, from my experience.

Prot: I 100% agree. I think that's the way to go. Just implement something so that it focuses the attention. Otherwise, you will get those endless discussions very quickly.

Sacha: Or try it as a package first, and then it can be core.

Philip: Excuse me?

Sacha: Oh, I was thinking if it's possible to prototype something as a package, now that Emacs has made it a lot easier for people to install packages, then at least it can be tested before having all the conversations about whether it should be as part of core or part of the splash screen or everything else.

1:10:42 Extending the core

Philip: The counter tendency I feel obliged to mention is that many times proposing something as a package or as an extension to the core can actually simplify the implementation vastly. Especially if you need to make one or two twists upstream and you need something like an additional hook or something to exist upstream. If it's a package in the core, then it's a lot easier to explain why you have to make this change than having to deal with some sort of advice and changing a lot of things. There was a certain tendency during the mid-2010s, which I only know from history, was to re-implement a lot of stuff in logs, in packages, instead of working on them upstream. That created a lot of divergence between packages, and in my opinion, complicated things because it introduces this entire choice fatigue. Should I use Flymake? Should I use Flycheck? Should I use LSP mode? Should I use Eglot? Which is not a historically accurate example in the stats that I'm given, But I'm certainly in favor of at least considering upstream contributions.

1:11:52 Guide to contributing to ELPA

image from video 01:12:27.567Philip: Even like packages, of course, it's the way we recently published these guidelines, or not guidelines, this contribution guide to publishing packages on ELPA, which is on, if you want to open it in the browser, it's on the ELPA homepage, which lists sort of these hard criteria which we require from ELPA. Just elpa.gnu.org, yeah, it's... That's going to be a link to the page.

Sacha: Yeah, this is pretty recent.

Philip: This is recent, and then there's a list of suggestions. But this is getting off the actual point. I'm just saying that relating to the general point, my experience is that proposing something concrete but also be open to hearing the opinions of other people These are the two necessary but maybe not always sufficient ingredients to making the changing stuff. Because if you just say, I want this to be different but don't put in the work, then everyone's going to forget it. But if you propose something and then insist that it has to be exactly this way, then you're just creating social tension. Maybe missing out on interesting things.

1:13:11 Making the newcomer experience better

Sacha: And especially since people are using Emacs for so many different reasons and coming from so many different backgrounds, what you are very firmly committed to might very well work for one set of people, but will run into these issues for all these other people. So if we want to bring it back to this, you know, how do we make the newcomer experience better? It's great that in core, there's starting to be a little bit more infrastructure for supporting things like sets of reasonable defaults for people. And maybe we as a community need to figure out, all right, how do we write documentation around it? How do we make tutorial videos? How do we encapsulate, okay, this is what this typical newcomer experience is like for this set of people and maybe these options or packages or a glue code might be helpful for this group? Maybe.

Prot: Yeah, like in theory, you can imagine something like, if you are a Python developer, here is your Python presets theme. If you are doing Org or whatever, here is your LaTeX and friends, right, and you could also have extensions like that in the future.

Philip: I mean nothing about the idea is... It could have been used as a package people can load otherwise.

1:14:30 "user option themes" versus "appearance themes"

Philip: And hopefully, as I said, there is certainly additional work which can be put in to support making user option themes better supported. I think one of the things that will be useful is actually referring to them just in nomenclature points as user option themes to distinguish them from.

Sacha: From themes.

Prot: From color themes, yeah.

Philip: Color themes, yeah. We even introduced the distinction that themes have kinds since like Emacs 20.

Prot: 29, I think.

Philip: 29.

Prot: I think you did that, right?

Philip: I think I worked on a patch. But that was exactly, I mean, that was already where the seeds for the current theme were started, because we wanted to distinguish between these different kinds of things. Were there any other questions?

Prot: I don't think so.

1:15:24 find-library

Prot: But yeah, as we saw now with the find-library that Sacha did in the beginning, it would be nice to also eventually be able to find the theme or whatever. Maybe it's a different find-theme, if for whatever reason it cannot be find-library.

Philip: That's actually no reason why that shouldn't be the case. I mean, you could just extend the logic to not only consider the load-list, but also the... Whatever the variable is for the list, then it should be able to find that as well, even though it's strictly speaking, that's a library. But that's a decision that someone has to make at some point or convince someone.

Sacha: I think find-library does work for it. Like, find-library will find it only if it's loaded. And then since I can't, like, undo it...

Prot: If it's a package...

Sacha: Yeah, yeah.

Prot: If you install it as a package, yes.

Philip: Because then the theme is in a directory which package.el has added to a load list. I think the preset, if my memory serves me correct, then find library only looks through load-path.

Sacha: I see, I see. And etc/themes is not in the load-path.

Philip: Exactly. Because these aren't, this is, I don't know why. It's not...

Sacha: Okay, all right. That's another message to emacs-devel.

1:16:49 configuration generator in Emacs? maybe more wizards?

Philip: It's the sort of annoyance which from my perspective is so inconvenient that I forget it every time and then you don't change it.

1:16:59 Starter kits

Sacha: @brongulus says the Doom Emacs module approach is very nice for beginners and entices them to get into things more. People interested in a certain common set of functionality can get an opinionated starting point in Emacs, rather than worrying about what to install. And someone else in the previous That's sort of like the theme approach, isn't it? Sort of, yeah. It's not just, hey, these are the packages and you can comment and uncomment lines that load the different modules, but also here's the glue to sort of start to make some of them work better together or to change them to reasonable defaults.

1:17:39 Configuration generator in Emacs Lisp?

Sacha: I was wondering, actually, along those lines, any thoughts about making your configuration generator type thing in Emacs?

Philip: The reason I, in the configuration generator, did not implement it in Emacs was precisely due to if it were in Emacs and would use, for example, something like the widget library and there would be these fine UI discrepancies which people wouldn't expect to behave the way they do, then scrolling doesn't behave exactly the way they expect it to do. But there has been an idea, I think, when I mentioned the configuration generator the first time. It was the notion of having actually a shared file format behind it, just some S expression, which could be loaded by both the configuration generator and a generic configuration wizard, which could also be used like every package could define their own configuration wizard for asking the user selected options and configuring these.

1:18:40 extending the archive format

Philip: That's also another thing in Emacs 32 which I plan to work on, to extend the package archive format. Among other things, allowing for multiple packages to be listed in it, because GNU ELPA and NonGNU ELPA both store multiple versions of all packages, but you can only install the most recent one. That's why pinning doesn't work. Absolutely no technical reason why this shouldn't also list other versions as well. And then you could have pinning without having to use Git. Packages as well. And there are a few others. There was a thread I think earlier this year where I collected a number of these extensions for the archive formats which could be extended. And now I forgot my thread. Now I lost my thread of those.

Prot: But basically extending package.el and the archive, yeah.

Philip: Specifically the archive, so that...

Prot: Showing the previous versions which are already listed, like you said.

Philip: Yeah, so that you could pin the version so you could install the version. I honestly do not remember what I was saying just a few seconds ago, which is embarrassing. Okay, that's another problem.

Prot: Things happen, no worries.

Philip: You were talking about Doom Emacs?

Prot: There was a comment about the Doom Emacs and specifically the fact that there are these modules and you can load the module without thinking specifically about the packages. But then Sacha told you about your package configurator wizard.

Philip: Package configurator wizard and then extending the metadata could also include this sort of configuration option. So that packages, in some sense, could specify what options the user would primarily be interested in and what order they should be traversed. And you could have some sort of dependency, of course. This is some effort which has to be put in, but it's not something that's unreasonable, from a technical perspective, from implementing this. And it would make, I think, it could make, if you have the infrastructure for that, that would make installing and using packages a lot nicer. It sounds very promising, for sure.

1:20:56 User interfaces

Philip: The UI question remains the thing. Do you want to reuse the Customize UI, which has its historical warts? Of course, can they be ironed out? That's a different question. Or do you reinvent something from scratch? And I'm usually not that big of a fan of reinventing the UI. I'm more in the reuse existing interfaces, just into the back end.

Prot: Plus, if you were to invent a new UI, you wouldn't have this new feature already because you have too many things that you need to implement. Whereas just using custom UI allows you to just implement the feature and then the interface, maybe it's something that somebody else will work on or you work on at the latest.

Philip: Yeah, but then, of course, that's... Even if that is the case, then you have to make sure that you don't make assumptions that depend on your own customizer in the future. It's a whole list of dependencies which is just complicated.

Sacha: That sounds like a newcomers presets to un-wartify Customize, a reset theme to put the warts back on as needed, and then we can use the slightly more modern interface for the things that we had wanted to do, maybe two or three years down the line.

Philip: Maybe something like that. A little long-term planning.

Prot: I think just to say this, but of course everything we have covered thus far, always we have to state it. Newcomers with an asterisk, right? With the caveat that you still have to put in the work, read the manual, be patient, all that, right?

Philip: Ideally, it would be nice if you could even start without it. I mean, I started without it, but it took me three or four years to actually write this one. I didn't want to write defun. I thought, what? I don't write my own functions. I just want to set options, which was wrong and appealing to this. That was the point from the beginning. But I think, Sacha, you wanted to close there.

Sacha: Oh, I just wanted to acknowledge that we are coming up in the 20 minutes that you said you were available for. Yeah, yeah, yeah, I need to go. Yeah, yeah, the dogs and everything.

Prot: Yeah, yeah, I have to take them for a walk because I have a meeting afterwards.

Sacha: Right. I wanted to thank both of you. I really like this conversation and the heads up and the interesting things coming down the pipeline. So thank you for that. We're going to continue, I think, working on the user experience for newcomers. which will probably be a mix of documentation and packages and other experiments and occasional email to emacs-devel suggesting things like the find-user-init-file and whatever. But thank you so much to you and to everyone who's tuned in.

Prot: You're welcome.

Philip: Thank you for hosting.

Prot: Thank you.

Philip: Thank you, Prot, for your comments as well.

Prot: Take care.

Philip: Bye-bye.

Prot: Goodbye, goodbye. Where do we close from here?

Philip: I'm just going to close the tab. Bye.

Chat

  • nick:protesilaos ​Hello folks!
  • nick:MichaelVash7886 ​hi
  • nick:protesilaos ​We still have a few more minutes. Looking forward to it!
  • nick:MichaelVash7886 ​ended up starting on doom and the nice thing is anything I want to try out is either in there or it's a simple tweak away. but it's several layers of abstractions to change certain things
  • nick:MichaelVash7886 ​for me to go from using doom to being able to program with a vanilla emacs I know it's going to be a journey to get things like completion, eglot, etc all setup
  • nick:MichaelVash7886 ​also looking at moving away from evil to using something like Meow and vanilla emacs binds
  • nick:lc2000 ​​Speaking of splash screen, there's still plenty of room, why not inline the GPL, and a small essay. Kidding of course, but what of slaying that sacred cow…?
  • nick:lc2000 ​(As it stands, it prioritizes ideology, laywer-mandated stuff from before case law, credits, funding via manual ordering… and if new users don't recoil some things they may actually need/want.)
  • nick:takoverflow ​​Hello Prot, Sacha and Philip!
  • nick:takoverflow ​Thanks for this discussion
  • nick:RandCode ​​greetings, everyone!
  • nick:RandCode ​​emacs has a place for chatting in all of irc, matrix, xmpp and telegram room! (also email)
  • nick:lc2000 ​​Packages are great at bundling functionalities, but Doom/Spacemacs/etc also fix the multi-package integration "glue", which technically could be packages (see all prior "config modules" attempts…).
  • nick:sachactube ​​https://bbb.emacsverse.org/rooms/chat
  • nick:protesilaos ​Come join us :)
  • nick:lc2000 ​Probably best to talk of modern de facto "standards" (vs full CUA as then-defined), e.g. if there's a "region" new users expect C-c (or C-c C-c in anger) to work, and idem C-x/etc - easy wins maybe.
  • nick:brongulus I do prefer the idosyncracies of with-eval-after-load and actually explicitly binding and creating hooks, rather than relying on use-package is that it tells me explicitly the order in which things would be evaluated. In contrast to use-package where I would have to know about defer and how to properly define the order of loading of different packages.
  • nick:Protesilaos @brongulus Fair point! I also like it. The thing with use-package is that you understand it better if you know what it does under the hood.
  • nick:brongulus This is where the doom emacs' module approach is very nice for beginners and entices them https://github.com/doomemacs/doomemacs/blob/master/modules/README.org
  • nick:brongulus People interested in a certain common set of functionality can get an opinionated starting point in emacs rather than worrying about what to install
  • nick:brongulus This is how it looks https://github.com/doomemacs/doomemacs/blob/master/static/init.example.el
  • nick:brongulus Thank you for the meeting o.

Some types of new users to think about

  • Non-programmer interested in using Org Mode for notes and task management
  • Researcher interested in publishing, reproducible research, literate programming
  • Programmer interested in coding with Emacs
    • Coming from VSCode
    • Coming from Vi
  • Programmer still using a different IDE, just interested in Magit
  • Long-time Emacs user who hasn't explored Emacs Lisp

Sketching out their learning journey

  • Install Emacs
  • Use Emacs via the menu bar and toolbar
  • Get a little overwhelmed
  • Use M-x to call commands by name
  • Learn how to set up completion
  • Use some keyboard shortcuts
  • Figure out how to learn and connect
  • Customize some options
  • Eureka!
  • Define their own keyboard shortcuts
    • Challenge: init file
  • Define their own functions
    • Challenge: Emacs Lisp

Other notes

Learning how to modify Emacs with Emacs Lisp can help people really appreciate its power. For example, you need Emacs Lisp to set your own keyboard shortcuts. You can't set them through the Options menu or the M-x customize interface. One challenge is that the Emacs Lisp configuration file that is loaded at the start of every Emacs session might be in one of several places, which means that in order for newbies to understand how to add something like:

(bind-key "C-c r" 'org-capture)

we need to either include a link to something like EmacsWiki: Init File, or repeat the instructions and the troubleshooting steps in beginner tutorials.

  • user-init-file defaults to .emacs for new users if none of ~/.emacs, ~/.emacs.el, ~/.emacs.d/init.el, and ~/.config/emacs/init.el exist.
  • After you select newcomer-presets from the splash screen, this is not persisted automatically. "Options > Save Options" doesn't save it either. Because people usually think of themes as cosmetic, they're not likely to find it under "Options > Customize Emacs > Custom Themes; newcomers-presets; Save Theme Settings." The "Options > Save Options" will save the change that newcomers-presets made to the tab bar, thus creating a ~/.emacs.
  • https://doc.emacsen.de/gallery.html - gallery of themes built into Emacs

Some screenshots of a fresh Emacs

2026-05-12_08-59-17.png
Figure 1: The splash screen for a new Emacs
2026-05-12_09-01-50.png
Figure 2: File menu
2026-05-12_09-02-43.png
Figure 3: Customize menu
2026-05-12_09-03-37.png
Figure 4: Help menu

Trying pkal's Emacs Configuration Generator

Emacs Configuration Generator - old source code, site is no longer live

sbcl --load ecg.lisp --eval "(ecg:start)"
2026-05-13_21-36-30.png
Figure 5: Web interface
2026-05-13_21-37-11.png
Figure 6: Theme preview, other options

Sample generated configuration:

;;; Personal configuration -*- lexical-binding: t -*-

;; Save the contents of this file under ~/.emacs.d/init.el
;; Do not forget to use Emacs' built-in help system:
;; Use C-h C-h to get an overview of all help commands.  All you
;; need to know about Emacs (what commands exist, what functions do,
;; what variables specify), the help system can provide.

;; Load a custom theme
(load-theme 'modus-operandi t)

;; Use whatever the default monospace font is
(setq font-use-system-font t)

;; Miscellaneous options
(setq-default major-mode
              (lambda () ; guess major mode from file name
                (unless buffer-file-name
                  (let ((buffer-file-name (buffer-name)))
                    (set-auto-mode)))))
(setq confirm-kill-emacs #'yes-or-no-p)
(setq window-resize-pixelwise t)
(setq frame-resize-pixelwise t)
(save-place-mode t)
(savehist-mode t)
(recentf-mode t)
(defalias 'yes-or-no #'y-or-n-p)

;; Store automatic customisation options elsewhere
(setq custom-file (locate-user-emacs-file "custom.el"))
(when (file-exists-p custom-file)
  (load custom-file))
View Org source for this post

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

-1:-- YE29: Sacha, Prot, and Philip Kaludercic Talk Emacs: Newcomer Experience (Post Sacha Chua)--L0--C0--2026-05-17T13:21:07.000Z

Irreal: Emacs As An Effortless Bloom

Charlie Holland has an interesting contribution to May’s Emacs Carnival, which this month is on the topic “If I may recommend…” His notion is that Emacs is an effortless bloom. The “effortless” part is because Emacs—contra conventional wisdom—is easy to use and can, in fact, significantly simplify your work flow by providing a uniform interface to several different computer programming languages and their environments. If you’ve ever had to negotiate such a collection, you know that this is not a trivial thing.

The “bloom” part is more nuanced. The idea is that like a rose whose roots “fan in” water and nutrients and whose flower “fans out” its petals and beauty to encourage pollination, Emacs has its own fanning in and out. The center of this action is the text buffer. Data from various sources can be fanned into a buffer from which it can be fanned out to various functions for processing. The altered text buffer can then be fanned out to other targets.

Holland’s post is a bit lyrical so you need to read it to get the full impact of his fan in, fan out metaphor. He considers whether any other editor could achieve the same power as Emacs. He concludes that any editor could, in theory, achieve the same power but in order to do so it would have to replicate the idea of the buffer as the single important data structure on which everything else operates.

It’s an interesting post worth a few minutes of your time.

-1:-- Emacs As An Effortless Bloom (Post Irreal)--L0--C0--2026-05-16T14:29:54.000Z

Jiacai Liu: My Thoughts on Bun's Rust Rewrite

Before we discuss Rewrite Bun in Rust, there's something that needs to be said, because no one is saying it.

Bun stands where it does today because of Zig.

Jarred chose Zig back then not because it was "cool," but because Zig enabled a small team to rapidly prototype a high-performance JS runtime without a GC, without a heavy runtime. Zig's low friction, direct memory manipulation, and straightforward C interop were the core reasons Bun could punch above its weight on performance with an extremely small team in its early days. The architecture, data structures, and low-level design of Bun that you see today – that was shaped by Zig.

-1:-- My Thoughts on Bun's Rust Rewrite (Post Jiacai Liu)--L0--C0--2026-05-16T03:59:54.000Z

Amin Bandali: FFS code review and Emacs extensibility with Protesilaos

In the recent weeks I've been engaging Prot as an Emacs coach to help with doing review passes over my upcoming ffs package as I work on polishing and documenting it in preparation for offering it for inclusion in GNU ELPA.

UPDATE 2026-05-15 08:50:10 -0400: Prot also published an article about our session on his website: https://protesilaos.com/codelog/2026-05-15-emacs-amin-bandali-ffs-display-buffer-org-capture/

Today we had our third session where we started by reviewing and talking about my recent changes to ffs, then ventured to other Emacs-related topics with the overarching theme of the flexibility and extensibility of GNU Emacs, including display-buffer-alist, keyboard macros, defining a custom ox-bhtml Org export backend derived from Org's ox-html for ultimate flexibility when exporting my site's pages from Org to HTML, Org capture, plain text files and Emacs's diary and how it compares to org-agenda, and keeping a journal with the help of Emacs.

Here is the video recording of our session, which I share with Prot's permission:

You can view or download the full-resolution video from the Internet Archive.

Lastly, here is the snippet Prot shared for having Isearch treat space as a wildcard, helpful for more easily matching multiple parts of a line:

(setq search-whitespace-regexp ".*?")
(setq isearch-lax-whitespace t)
(setq isearch-regexp-lax-whitespace nil)

Take care, and so long for now.

-1:-- FFS code review and Emacs extensibility with Protesilaos (Post Amin Bandali)--L0--C0--2026-05-15T02:55:33.000Z

Protesilaos: Emacs coaching with Amin Bandali about ffs, display-buffer-alist, Org, and more

Yesterday I met with Amin Bandali to talk about Emacs. Amin asked me if he could record the session, which I agreed to. The video is available on Amin’s website: https://kelar.org/~bandali/gnu/emacs/ffs-emacs-ext-prot.html.

We started with a review of the latest changes to the ffs package that Amin has been developing. We had looked into it before and wanted to check on its current state.

Amin then asked me about the display-buffer-alist, which I had mentioned before. To me, this is the single most important variable for making Emacs feel more like your own. The reason is that it allows you to control the placement of buffers to match your expectations. I demonstrated some of the main ideas.

Another nice little feature is the built-in isearch. I explained how it is especially helpful while recording keyboard macros. Though it is nice to use in general. One tweak for it is to display a counter with its matches. Another is to change how it treats spaces, so that it can match any character in-between. This is not as flexible as, say, consult-line (from the consult package) when combined with vertico and orderless. Though it still has its uses.

[ I have lots of little extras for isearch, but those should be good for most users. ]

Amin told me about rediscovering the value of Org in the context of statically generating his website. He showed me the custom Org HTML export backend he has been working on. Org has so many nice features which can be used independent of each other. In this light, we also discussed the diary compared to the Org agenda.

Find all of Amin’s publications on his website: https://kelar.org/~bandali/.

-1:-- Emacs coaching with Amin Bandali about ffs, display-buffer-alist, Org, and more (Post Protesilaos)--L0--C0--2026-05-15T00:00:00.000Z

Irreal: Emacs And The Bazaar/Git Saga

Thanos Apollo has an interesting post about an almost forgotten Emacs battle: the choice between Bazaar and Git as the new version control system for Emacs. Twenty years ago, Emacs was still using CVS, a venerable RCS that was well past its sell date.. It was clear to everyone that a new system was needed. The question was which one. The two contenders were Bazaar and Git.

On the technical merits the choice was clear. Git was faster and more reliable and most, if not all, of the developers wanted to move to it. But there were political considerations. Bazaar was a GNU project and Git was not. RMS felt strongly that the GNU project should support its own applications and insisted that Bazaar be used and given a chance to improve. It was maintained by Canonical but they eventually abandoned the effort. Even though the development was stalled and error reports were piling up unresolved for years, RMS insisted on staying the course.

The saga would probably still be going on were it not for Eric Raymond (ESR). He had been working for some time on a utility to import various RCS systems into Git while maintaining whatever metadata the old system offered. At one point he decided to convert Emacs to Git. It was a particularly difficult problem because there was more than one source RCS in play and because some of the records were old and incomplete.

Nonetheless, ESR managed the conversion and in 2014 announced that he had the conversion scripts ready and was set to go. In November 2014 he ran his scripts and suddenly Emacs was available as a Git repo. The developers started using it and the battle was over.

-1:-- Emacs And The Bazaar/Git Saga (Post Irreal)--L0--C0--2026-05-14T14:45:38.000Z

Dave Pearson: Stopping an accidental push

After starting to make use of the GitLab/Codeberg sync approach for various repositories, I found that my muscle memory in Magit was getting the better of me and, on occasion, I'd push a new branch to backups when I wanted origin. I sensed there had to be a way round that.

Here's what I settled on:

(advice-add
 'magit-list-remotes
 :filter-return (lambda (remotes) (delete "backups" remotes)))

Now I never see backups in Magit and now I can keep using my muscle memory (rather than actually reading what is in front of me, it seems).

-1:-- Stopping an accidental push (Post Dave Pearson)--L0--C0--2026-05-13T18:04:49.000Z

Charlie Holland: May I recommend&#x2026; understanding Emacs's patterns

1. About

emacs-carnival-may-banner.jpeg

Figure 1: JPEG produced with OpenAI gpt-image-1

What's in a name? That which we call Emacs
By any other name, works just as well;
Our editor could, were it not an Emacs call'd,
Retain those perfect patterns which it owes
Without that title. Emacsen, doff thy names,
And for those names, which are no part of thee,
Take all my code.

The above, unless I've completely forgotten my Shakespeare, was a soliloquy from Juliet Consulet regarding Romeo Montagnu

"Emacs is an Effortless Bloom," or at least, this is what my brain has been screaming into its own void for the past few months…. (by the way, there is a better simile).

I have recently been publishing posts to my blog as part of a composite series on the usage patterns that make Emacs powerful to its most fluent users. I don't know if "Emacs is an Effortless Bloom" will be the name of the series when all is said and done….

Maybe it's more of a mantra, or perhaps even a haunting brain spasm at the moment. At least, this phrase has been popping involuntarily into my mind since I started this series, and I think it's worth thinking about why.

In this post, I'll discuss, among others, two core patterns that make Emacs easy and powerful, Incremental Completing Read and recognize-dispatch.

If you find the prose herein flowery, it's because it pertains to flowers 😉.

2. "Effortless"

My goal of the series is to promote Emacs usage by conveying how and why it makes computer use easier. I feel Emacs gets a bad rap in the broader society of builders because there is a common notion that it's arcane and complicated and, therefore, difficult to use. I do believe this notion is a false one, and much of my writing and talking about Emacs revolves around precisely why Emacs makes using a computer easy.

When I tell folks "I use Emacs", I typically get some kind of "Wow, good for you" or "that's impressive!" or "I wish I could use Emacs, but I never had the time to grok it". Despite the flattery, I always feel dejected by these comments, especially as a lonely advocate for its use and a firm believer that using Emacs is easy.

It is largely this misconception that motivated me to write my series, and hopefully in doing so I can dispel the notion that Emacs is some nuclear wand only to be brandished by the lisp era's most considerate wizards.

3. "Bloom"

This one is not self-explanatory, and the word came to me before its justification… it just felt 'right'. As I continue to think critically about Emacs's patterns and why they make computer use effortless, I can attribute a few significances to this word.

3.1. Bloom as in Blossom

First, when I started using Emacs, it really did make me feel like I had come into my own as a builder.

I had a somewhat unconventional entry point to Emacs. I had just learned Visual Basic for Applications (VBA) in order to automate clinical research workflows at a research institution. This was my first job, and my first foray into the world of automating via programming. Learning VBA was an almost indescribable stepwise increase in my power as a computer user and builder of clinical research workflows. But that ability lost its leverage quickly….

As the data practice in our research firm outgrew the memory and performance constraints of Excel + VBA, I found that I needed to learn 3 new languages to support our operations: SQL for data extraction from our data warehouse, Python for automated workflows, and the researcher-friendly R for analysis and predictive modelling.

With this polyglot burden came another one: I needed to learn 3 new GUIs to be able to write and execute the programs I'd written in these 3 languages. Not only was this daunting, it was also uncomfortable. My glorious unified experience of doing everything in VBA now had the friction of context switching between different GUIs, all with different usage paradigms, patterns, and keybindings.

I recognized what underpinned my dread in this brief but tumultuous phase: the incidental complexity of adding languages to my toolbelt scaled somewhat worse than linearly with the number of languages. For every 1 new programming language I wanted to speak, I would have to learn at least 1 new interface modality to support that. I knew I was good at learning languages (and bad at learning GUIs), so how could I escape this friction?

As if from some theophany, Emacs came to me in an article I was reading about how Unix works. It was mentioned off-hand, in a single sentence, but with a compelling label as the 'most powerful, programmable editor'.

Huh… I thought "if I (and indeed anyone else) can program the editor, maybe I can work with all these languages and runtimes in a single environment". After watching dozens of Emacs demos on YouTube, I became convicted that this was indeed the case. Shoutouts are well deserved here for Magnar Sveen's Emacs Rocks, Mike Zamansky's Using Emacs, and Aaron Bieber's (no relation) very brave pitch on Emacs that he delivered at a vim conference.

Before I had seen the light of Emacs, I felt uncomfortably bounded and acutely constrained by the possibly infinite number of new tools I would need to grok in order to become a polyglot. This infinite expanse of tooling came with an ironic feeling of claustrophobia. But with Emacs, those bounds seemed to disappear, and I felt like my mind was able to 'blossom' in the fertile soil of Emacs's rich and endlessly configurable environment.

3.2. Bloom as in the Roots Fan-In, the Petals Fan-Out

Picture a rose, a purple one if you could (as we are talking about Emacs here).

On one end, the rose has roots, pulling in nutrients and dihydrogen oxide through a complex and ever growing tendrillic network. At the other, we see the rose's beautiful flowering of petals: the outcome of all this rose's growth, the attractor of admiring eyes, and the basis for proliferation through pollination. Emacs's patterns, architecturally, remind me of this kind of flowering because we can see that Emacs fans-in and fans-out in the same beautiful and life-giving ways as our purple rose's roots and petals do.

Consider the buffer. Anything you look at in Emacs (no need to enumerate, I literally mean everything) is a buffer of characters with text properties layered on top. I'm simplifying a little bit, but that's pretty much it. That standardization is the core data model from which everything else grows.

The roots of the rose look the same whether they're pulling minerals from clay, soil, or sand (it's all just water and ions in the end). In Emacs, any thing is pulled into just characters and properties in a buffer (fan-in). The corollary is that every editing primitive you learn — search, kill, mark, narrow, replace, undo, blah blah blah — works against every piece of content you'll ever look at in Emacs, because nothing is special with respect to this data model, and no exceptions will be found. The characters + text props is the unifying idea, and the buffer in which they reside offers a universal vocabulary with which you can speak into Emacs whatever your heart desires, Juliet 😉.

On top of that vocabulary sits Elisp, and on top of Elisp sit the applications. Whatever you can likely imagine (Email, RSS, calendar, version control, file management, IRC, music, financial ledger, terminal, etc…) is a small Elisp program that puts text into a buffer (often with a specialized major-mode) and binds keys to commands that transform and navigate that text.

There is no fundamental linguistic difference between something as complex as Magit and something as simple as a mode I may write to depict an ASCII rose in a popup buffer. The elisp entities powering those modes live in the same namespace, share the same APIs, and adhere to the same Emacsien and Elispien conventions. This is the deeper meaning of 'interface unification': you don't merely view different things through one interface (which is valuable by itself). Instead, you build, extend, and rewire them through one interface. And if a use case doesn't have an application yet, building one is easy, because you have the full power of Elisp.

The next pattern lives at the input layer, and is evocative of many an 'at-your-fingertips' metaphor. When Emacs asks you to choose something (files, buffers, commands, or indeed a candidate from any context) it doesn't ask you to remember what you're looking for verbatim. Incremental Completing Read (ICR) drastically reduces the burden of recall when searching for anything when you're inside of Emacs, and the flexible filtering offered, for example, by packages like Orderless, make the resulting candidate set small and specific enough that recognition is often trivial.

ICR in Emacs can take whatever set of candidates is in play and filters it live as you type, ranking by recency and frecency, fuzzy-matching, re-sorting by relevance, etc…. When you hit M-x (to run a command), you don't have to know the exact command name; you simply have to know, or perhaps more accurately 'intuit', enough of its shape to narrow the field. And because every domain in Emacs eventually exposes its candidates through the same minibuffer mechanism, the entire universe of things-you-might-want pulls through a single, deeply familiar selector (fan-in). At runtime, you can materialize and search this universe (fan-out) with only your tiny, fuzzy notion of what you're looking for. This recall facility is something that makes using Emacs powerful, but also cognitively ergonomic. Like with buffers + text + props, you'll find after a while that most of your Emacs usage funnels through this unified interface of minibuffer completion.

ICR is only part of this story. After you've selected your candidate, what can you do with it? Emacs cheekily answers "what can't you do with it!", and more helpfully adds "let me show you exactly what you can do with it". This comes from an implementation of what I think of as the recognize-dispatch pattern.

In most software, the answer ("what can I do with this thing on the screen") is hardcoded to a single default action: the open-file dialog opens files, the contact picker picks contacts, and so on. Packages like Embark and Hyperbole change the cardinality here for the better.

Any "thing" (which is a funnily loaded word in Emacs land) on which you can place your cursor (file path, a URL, a symbol, a region, etc…) has a type, and that type has a menu of actions associated with it. Because both the types and actions are extensible, Embark offers the ability to assign a specific type (or set of specific types) to anything that appears in Emacs (fan-in) and enables you to take any action on that thing (fan-out).

In this way, for example, a symbol is a thing you can describe, jump to, occur, rename, search the web for, hand to an LLM, ad infinitum…. A file is a thing you can open, diff, copy a path to, rename, attach to an email, ad infinitum…. The "infinitum" part is quite literal, especially when you consider that you can use any parameterized command as an Embark action (you aren't limited to what's in the defined menus). In this way, the actions accrue as you continue to extend Emacs. When you install a new package (fan-in), suddenly all your existing nouns, or types, gain new verbs, or actions (fan-out).

Also consider how, with Emacs, you can achieve the same kind of piping paradigm you would with a Unix shell. In a spiritual recovery of the 90's era CLIM (Common Lisp Interface Manager) implementation of presentation-types, output of some command in Emacs can be input to another via this recognize-dispatch system. The snake eats its tail, somehow in a non self-cannibalistic manner, just like in the all-powerful Unix shell.

An especially enabling set of actions that you can add in this way is provided by language servers in Emacs. For decades, "go to definition," "find references," and "rename symbol" were the exclusive privileges of IDEs that had been hand-coded (and price-tagged) for a specific language. The Language Server Protocol (LSP) externalizes that introspection into a per-language server that speaks a common format. Emacs (via eglot or lsp-mode) talks to the server, the server reports types and locations, and Emacs renders the result into a buffer. The upshot is that Emacs's existing typed-thing machinery inherits the introspective powers of a language server, in every language that has one (fan-in). The cost of literacy in a new language collapses (yay for me!), because the editor doesn't have to learn anything new; only the server (or the implementer of the server) does. In this way, you can effortlessly navigate, code, and execute in any language (fan-out) using the same usage pattern.

There is so much power in this pattern: recognize the noun, dispatch a verb. Pour all instances into a single channel (fan-in); radiate out from that channel with the full force of every extension you've ever installed (fan-out).

This fan-in, fan-out occurs at the application level as well. Take elfeed, for example, the leading RSS reader in Emacs. All the vagaries of any news source you subscribe to funnels its new items into a flat list (fan-in) in an elfeed-search buffer, and all the Emacs facilities that work in any other mode are available to you as you navigate and consume these news sources (fan-out). As another example, take mu4e, a popular email package for Emacs. Emails from all your email addresses, again, are funneled into a single flat list (fan-in), and you have all the power of Emacs at your disposal to navigate mail, read, and respond (fan-out).

The rose has the structure it has because it works, and many years of evolution have brought its beautiful form and function to bear.

The bloom:

Pull broadly, push narrowly; pull narrowly, push broadly.

With recognize-dispatch, pull broadly everything into text buffers, push narrowly into an actionable type system; pull narrowly from that sparse set of typed things, push broadly into any conceivable action.

Any search or selection you need to do inbetween is made effortless by ICR, where, by the way, types and actions are still available (thanks to Embark). Pull broadly any candidate source into Emacs and push narrowly into the minibuffer's ICR system; pull narrowly from a filtered candidate set and push broadly into any conceivable action on your selection.

You can even see the two patterns work gracefully in concert: consider dispatching a huge action menu for a generic target. You don't want to manually scan through the which-key buffer to select that action, so you can use embark-help to run ICR and select your action that way. Beautiful!

Emacs's patterns aren't incidental. They're something closer to the right answer to a question every aspirationally generic tool eventually asks, which is "how do you make one interface stand in for many, without losing the specificity of any"?

4. A better simile

My simile for Emacs is the blooming of a rose…. Oh, Romeo, why did you do such a thing!

I have to come clean and admit that this simile (maybe more honestly a metaphor) is highly contrived (this is a sideshow in a carnival after all 😜), and I did feel the cognitive dissonance when trying to shoehorn this rose metaphor into the fan-in/fan-out meta pattern of Emacs.

There is another, better, way to think about this pattern.

Gwern Branwen, of gwern.net, provided a much better simile on this post's r/emacs thread: "You could also consider your 'bloom' to be a 'bow-tie network', which is good for end-to-endianness: bow-tie network https://gwern.net/ref/csete-doyle-2004 https://gwern.net/doc/biology/2004-csete.pdf"

Gwern's comment paints a much more faithful and insightful simile for the Emacs meta pattern, and it actually sharpens my own understanding of this pattern. And to my surprise 🤯, Gwern's excerpts from Marie Csete and John Doyle's "Bow ties, metabolism and disease" paper actually mention the fan-in, fan-out phenomenon explicitly, albeit without the ugly hyphens I used in this post:

"As shown in Figure 1, a myriad of nutrient sources are catabolized, or ‘fan in’, to produce a handful of activated carriers (eg. ATP, NADH and NADPH) and 12 precursor metabolites (eg. glucose 6-phosphate, fructose 6-phosphate, phosphoenolpyruvate and pyruvate), which are then synthesized into ~70 larger building blocks (eg. amino acids, nucleotides, fatty acids and sugars). The precursors and carriers can be thought of as two ‘knots’ of separate bow ties that are both fed by catabolism, but whereas the former ‘fan out’ locally to the biosynthesis of universal building blocks, the latter fan out to the whole cell to provide energy, reducing power and small moieties."

The bow-tie's appeal, aside of course from sparing me the apology for being silly and contrived 😉, is that it names the function of the narrow part, while the rose thing tenuously names its shape. A rose has a stem, sure, and the stem does technically connect the roots to the bloom…. But the stem is mostly a passive conduit. The bow-tie's knot is where the action happens. In metabolism, the knot is the small set of activated carriers and precursor metabolites, and then every nutrient that gets catabolized has to pass through that knot to become anything else. The knot is the universal intermediate currency. And like Csete and Doyle point out, there's more than one of them!

In Emacs, one knot (not the knot, I'll explain in a moment…) is the buffer: characters with text properties. Every input (again I will spare the enumeration as I do literally mean everything) passes through that narrow representation in order to be looked at, edited, searched, or acted on. And every Emacs facility (again sparing the enumeration) operates against that narrow representation.

Csete and Doyle even anticipate the multi-knot layering I was missing with the contrived rose thing in my sideshow.

They describe the "precursors and carriers" as "two knots of separate bow ties", each having its own fan-in and fan-out.

Emacs has the same multi-knot structure. The buffer-plus-text-properties is one (of many) knots in Emacs, and as previously mentioned, is the foundational one. ICR, separately, is its own bow-tie, with its own narrow waist, and Embark/Hyperbole (inspired-by or harmonizing-with CLIM's presentation-types idea) is yet another. And there are more and more (see my blabbering on RSS feeds and emails above).

What's especially better about Gwern's simile is that the bow-tie shape itself isn't unique to metabolism or to Emacs. Among other things, I'm sure it's why the Unix shell is the way it is, with plain text streams (pipes for the win!) as its universal intermediate.

As a final note, I think it's absolute fascinating and thought provoking that the best simile I can identify for Emacs's meta pattern comes from the study of biochemical systems. I have nothing profound to say about that, I just think it's ruddy interesting.

5. Emacs by any other name

Emacs is not magic, and exactly zero of the patterns I've described are intellectually proprietary to it.

A few patterns have already begun to leak out. The Language Server Protocol, in fact, wasn't invented for Emacs. It was invented at Microsoft for Visual Studio Code, and the rest of the editor world (Emacs included, via eglot) caught up. ICR-style recognition-over-recall pickers have shown up as command palettes in VS Code and Sublime Text. And plugin systems of course exist in nearly every modern editor. So the question is fair: What's in a rose?. Could another editor be Emacs, given enough effort? In principle, yes.

But in practice, the difficulty isn't any one pattern, but instead in the composition of those patterns. The gander is much greater than the sum of its geese, and in Emacs, the patterns synergize with each other, while somehow staying out of each other's way.

The patterns all 'play nice in the sandbox' if you will, but they can play more fortuitously as a team. Embark's typed-thing dispatch is only as good as the ubiquity of buffers and text properties beneath it. If half your "things" live in special-purpose UI widgets that aren't presented as text-in-buffers, then Embark woefully can't see them. ICR is only as good as the standardization of candidates. Even LSP — the most ubiquitous pattern leveraged outside of Emacs — only delivers its full potential when the editor already has a uniform "thing under point" model to which the server's responses can attach, and from which Emacs's fan-out action system can be dispatched.

There's also a sociological aspect to this. The patterns crystallized out of the Emacs community precisely because the community is philosophically aligned with discovering them. Everything is Lisp; every interaction is inspectable, hookable, redefinable. New patterns surface, get implemented as packages, and interestingly, many of these new patterns get factored upstream into the Emacs source. While any other editor could, in theory, be another Emacs, those editors that want to import the patterns wholesale would have to import the conditions that produced them and promote the culture that supported them.

But none of that is to say it's impossible. If a future editor actually delivered the full stack of patterns (text buffers as universal substrate, a Lisp-equivalent extension language with shared namespace, ICR, Embark/Hyperbole-style typed dispatch, LSP-style introspection, the fan-in/fan-out logic of one channel for everything), then it would definitively be powerful in the same way Emacs is powerful. Whether we called it Emacs or not would be arbitrary nomenclature.

Which brings me, predictably, to Juliet:

What's in a name? That which we call Emacs
By any other name, works just the same;
Our editor could, were it not an Emacs call'd,
Retain those perfect patterns which it owes
Without that title. Emacsen, doff thy names,
And for those names, which are no part of thee,
Take all my code.

-1:-- May I recommend&#x2026; understanding Emacs's patterns (Post Charlie Holland)--L0--C0--2026-05-13T17:00:28.000Z

Irreal: Cl-flet, Cl-letf, And Cl-labels Explained

A few weeks ago, Bozhidar Batsov had a splendid post on cl-flet, cl-letf, and cl-labels. I didn’t get a chance to write about it then but his post is very useful for understanding these macros and how they differ.

The macros are the replacements for the now deprecated flet, which, in turn, was imported from Common Lisp with the added feature of having dynamic scope. As Batsov points out, making the scope dynamic conflates the notion of local and dynamic scope, which can be a bit confusing. This behavior is preserved by the cl-letf macro for those who need it.

The cl-flet macro is just like the flet macro from Common Lisp. It defines a local function whose definition is available only from within its scope. The salient fact is that its definition is not available from within the function definition so it can’t be called recursively.

The cl-labels macro is like labels from Common Lisp. It’s similar to cl-flet except that its definition is available from within the function definition so it is recursive.

Finally, the cl-letf macro largely replicates the behavior of the old (Elisp) flet macro with the addition that it can dynamically replace the definition of any setf-able definition. This can complicate its use a bit. See Batsov’s post for the details.

If you’re like me, you don’t use any of these macros that often so it’s easy to forget the details. For that reason it’s worthwhile bookmarking Batsov’s post so that you can refresh your memory whenever you need to.

-1:-- Cl-flet, Cl-letf, And Cl-labels Explained (Post Irreal)--L0--C0--2026-05-13T14:33:25.000Z

James Dyer: A Tiny Nohup: Keeping Media Alive When Emacs Exits

This post is simply about some more yak shaving and there was this one niggle that I just kept putting off, because it never really annoyed me enough, but recently I started watching a lot more video content from within dired and it finally got to me.

The problem. I press W in dired, which is bound to dired-do-async-shell-command, type mpv (or accept the default guess that my dired-guess-shell-alist-user provides for video files), and the video starts playing. Great. But when I close Emacs, the video dies too. The whole point of an async command is that it runs in the background, right?, so why does it disappear when Emacs goes away?, this is most perplexing!

20260512184707-emacs--A-Tiny-Nohup-Keeping-Media-Alive-When-Emacs-Exits.jpg

Now I should say, the answer is obvious in retrospect, but it took me a little while to actually stop and think about it properly. The command dired-do-async-shell-command adds a trailing & to the shell command and passes it to async-shell-command, which creates a shell process - Emacs is the parent of that shell, and the shell is the parent of mpv. When Emacs exits, it kills its child processes, the shell goes down, and mpv gets orphaned, which is fine actually, the problem is not being orphaned, the problem is that it receives a SIGHUP from the process group cleanup and dies before it can be reparented to init. So the media stops.

The solution is a single, tiny piece of advice. I just prepend nohup to the command string before dired-do-async-shell-command does anything with it. nohup makes the process ignore SIGHUP, so when the shell gets killed by Emacs, mpv is orphaned cleanly and keeps running.

(defun my/dired-async-shell-command-nohup (orig-fun command &optional arg file-list)
  "Wrap COMMAND with `nohup' so the process survives Emacs exit."
  (funcall orig-fun (concat "nohup " command) arg file-list))

(with-eval-after-load 'dired
  (advice-add 'dired-do-async-shell-command
              :around #'my/dired-async-shell-command-nohup))

That is it. Six lines of Elisp, five of which are boilerplate.

And yes, this works for any command you run through W, not just mpv. gimp, firefox, libreoffice - they all get the nohup treatment now. Which is fine, those programs usually detach themselves anyway, but it does not hurt to have it.

So that is the tweak. A tiny, one-function, one-advice change that finally stopped my videos from dying every time I closed Emacs. I suspect someone will tell me that there is a simply variable flag that I can set that enables this anyway, but hey ho!

-1:-- A Tiny Nohup: Keeping Media Alive When Emacs Exits (Post James Dyer)--L0--C0--2026-05-13T09:53:00.000Z

Bicycle for Your Mind: Alfred Liberates Keyboard Commands

Keyboard CommandsKeyboard Commands

I ran out of keyboard commands.

OK, that sounds weird. Let me explain. In Alfred, I have the following keyboard assignments:

⇧⌃A: App Store
⇧⌃B: BBEdit
⇧⌃E: Emacs

I had covered the alphabet. Every letter had an application associated with it. I started a second layer. I assigned ⇧⌃⌥B to Better Finder Rename, ⇧⌃⌥E to EagleFiler and so on. Soon I was running out of choices again.

Over a period of almost 15 years, I made do. I loved Alfred, I also loved keyboard commands. I wanted to be able type a keyboard command and then choose from a list of applications which were tied to that keyboard command. I wanted to be able to type something small to be able to navigate this list and launch the application I wanted.

I didn’t know how to do this in Alfred. I had hacked together a solution in Keyboard Maestro, but I wanted to do it in Alfred. It was my launcher. So, I went to the Community for Alfred and asked, Choosing to launch particular programs with a shortcut - Workflow Help & Questions - Alfred App Community Forum. FireFingers21 answered with a workflow.

FireFingers21’s solution had two parts:

  1. The ability to assign a keyboard command to a workflow which would give me a list of applications assigned to it. I could press the keyboard command and then choose from a list by typing the number corresponding to my choice. Hit ↵ to launch.
  2. The ability to assign a keyboard command to a workflow which presented a similar list. This time the list could contain multiple applications grouped together.

This Is How It Helped

OutlinersOutliners

Previously, I had ⇧⌃O assigned to open OmniOutliner. The same command now gives me the ability to launch OmniOutliner, Zavala, or Opal, depending on my needs. This is now the Outliner keyboard command.

EditorsEditors

⇧⌃E, opened Emacs. Not anymore, now it can open any of these programs. Don’t laugh. I am aware that I have too many editors installed.

MultiMulti

I have Hyper-A assigned to multi-application launches. Every morning I used to start my workday by pressing Hyper-A and that would launch:

  1. SpamSieve
  2. Mail
  3. Safari
  4. Ghostty

Now it gives me a choice. I can also launch my updates group:

  1. Applite
  2. Mac App store
  3. Latest
  4. Wailbrew

One keyboard command, groups of multiple applications launched together.

Conclusion

  1. I have keyboard commands to spare.
  2. Alfred is a great product. I knew that.
  3. The community around Alfred are helpful and informative.
  4. Don’t hesitate to ask questions when you don’t know how to do something. There are helpful people around who might have the answers and they are willing and ready to help you.
  5. Thanks to FireFingers21 and Vero for their help.

Note: Thanks to Darren Halos for the picture.

macosxguru at the gmail thingie.

-1:-- Alfred Liberates Keyboard Commands (Post Bicycle for Your Mind)--L0--C0--2026-05-13T07:00:00.000Z

Irreal: Context Menus for Elisp Development

Charles Choi is back with more menus. Most of you know that I generally eschew the use of Emacs menus but they definitely have a place in seldom used commands whose name or key shortcut are hard to remember. In most cases, it’s possible to play around with fuzzy command completion and find what you’re looking for but it’s a lot easier to simply use a menu if it’s there.

That’s where Choi’s latest update to Anju comes in. He says that the introduction of context-menu-mode in Emacs 28 made it possible to provide cotentxt sensitive menus for Elisp development and he has added it to the latest version of Anju.

His post has a couple of screen shots of his menus in action. In the first, the point is on a function definition and the menu, among other things, offers the choice to instrument that function. In the second, the function has been instrumented and now the (context sensitive) menu offers things you can do—such as step into, set a breakpoint, and others—with the function. Naturally all of this is dependent on where the point is. That’s the point: the menu is context sensitive.

Choi says that the use of the context menus has markedly improved his Elisp development. If you do some but not a lot of Emacs development, it may be a win for you. On the other hand, Choi certainly does do a lot of Emacs development and still finds it a win. Perhaps—no matter your normal workflow—you will too.

-1:-- Context Menus for Elisp Development (Post Irreal)--L0--C0--2026-05-12T15:27:37.000Z

Bozhidar Batsov: Port: a minimalist prepl client for Emacs

For ages I’ve had “add prepl support to CIDER” sitting somewhere in the back of my head. CIDER is built firmly around nREPL, but prepl ships with Clojure itself, and the appeal of dropping the external REPL server requirement is obvious. Recently, as part of a broader internals cleanup “mini-project” in CIDER, I finally sat down and put a prototype together: cider#3899.

The good news is that the prototype sort of worked. The bad news is that the more I poked at it, the more I kept running into the same pattern. CIDER assumes ops, sessions, request ids, and a whole structured protocol that prepl simply doesn’t have. The amount of CIDER code that would need to grow “is this nREPL or prepl?” branches added up quickly, and I’d be papering over prepl’s limitations in dozens of subtle places. The exercise was fun, but it ended up reaffirming my long-standing belief that nREPL is a much better fit for editor tooling than prepl is.

The exercise did leave me thinking though. What if, instead of bolting prepl onto CIDER, I built a small standalone client in the spirit of inf-clojure and monroe? Something tiny and focused that doesn’t have to pretend to be CIDER, and where prepl’s quirks would be the design rather than something to work around.

Conveniently, I was on vacation in Portugal at the time, where I spent a few days in Porto, and the name pretty much picked itself. Port was born. It kept us firmly in the land of fun, drink-inspired Clojure-on-editor names: CIDER, Calva (after Calvados, the apple brandy), and now Port (the famous fortified wine). The protocol Port talks to is prepl, over a TCP port, so the pun was hard to pass up.

This time around I didn’t manage to land on a backronym I love (at least not yet). The contenders so far:

  • prepl omnipotent repl toolkit (my favorite so far)
  • prepl-operated repl toolkit
  • peak optimized repl toolkit

Naming is hard. I remain open to better suggestions. :D

Scope, or what Port isn’t

Port is a side project. I don’t plan to invest serious time in it past the point I consider it feature-complete, which won’t be far beyond what’s already there. The deliberate goal is to keep it simple and focused, and its feature set will stay close to inf-clojure and monroe. Port is not competing with CIDER. If you want the full feature set (debugger, inspector, test runner, profiler, structured stacktraces, refactor support), CIDER + cider-nrepl is, and will remain, the way.

What Port gives you today is a small, dependable Clojure REPL that you can hook into Emacs without any external dependencies, just a stock Clojure JVM with a prepl listening on a port.

A few architectural notes

If you’re up for the long version, doc/design.md goes deep. Here’s the short version of what prepl gives you compared to nREPL:

  • No bencode. prepl emits EDN-tagged maps, one per line. This might be a feature or a problem, depending on your perspective.
  • No middleware. Whatever the server prints is what you get. No interception, no extension surface.
  • No sessions. There’s one thread per TCP connection.
  • No ops. You send a Clojure form, the server evaluates it, and prints back tagged messages: :ret, :out, :err, :tap, plus an :exception true flag on errors.
  • No request id. This is the main issue. Tags identify the kind of message, not which request produced it.

That last point is the central design constraint. If you want to issue a request and reliably read back its result without accidentally consuming output from an unrelated background future or tap>, you need to layer correlation on top of the protocol. Port does this with two tricks:

  1. Two sockets per session. A user socket drives the REPL buffer with raw streaming output, and a separate tool socket carries helper-command requests. Background prints from future/agent on the user thread don’t bleed into the tool channel.
  2. A bootstrap form. On connect, the tool socket evaluates a one-shot form that defines a port.tooling/-eval wrapper. Every subsequent helper call goes through it, which captures *out* / *err* and returns a tagged map containing the request id. The client matches the id against a pending-callback registry.

This is what nREPL provides via sessions and ops, just reinvented at the TCP layer. It’s a fair amount of work for something nREPL gives you for free, which only strengthens my view that nREPL is the better protocol for editor tooling. Still, it was an interesting and educational exercise.

Zero dependencies

One thing I’m fairly proud of: Port has no hard dependencies. You’ll want either clojure-mode or clojure-ts-mode installed for the source-buffer side of things, but Port itself only soft-depends on them via runtime fboundp checks. Hook it onto whichever one(s) you actually use. I intend to keep it that way. Dependency creep is a real problem in the Emacs (every?) ecosystem, and a small package should stay small.

What’s there in 0.1

I tagged v0.1.0 yesterday. It’s small but already perfectly usable:

  • M-x port “jacks in” (bootstraps) (auto-detects deps.edn / project.clj / bb.edn, starts a server and connects to it)
  • single-buffer REPL with persistent input history, completion, and eldoc at the prompt
  • interactive evaluation from source buffers with pretty-printed results
  • structured stacktrace buffer with cause chain and navigable frames
  • M-. find-definition that follows into jar sources
  • doc/source/apropos/macroexpand helpers

MELPA submission is queued up next. After that, expect Port to be in burst-driven maintenance mode like most of my smaller projects.

Feedback, ideas, and contributions are most welcome. The issue tracker is the right place.

Closing thoughts

Funny thing, I’d never actually written any code against prepl until I started this project. It was fun to spend some quality time with the “competition” of my beloved nREPL. Working with a different protocol always teaches you something about the one you’re used to, and I came away from this with a renewed appreciation for both: prepl is genuinely elegant for what it is, and nREPL is genuinely well-designed for what we use it for.

Big thanks to Clojurists Together and everyone else who supports my OSS Clojure work. You rock! Now if you’ll excuse me, I have new releases of CIDER, clj-refactor, and refactor-nrepl to get back to.

Keep hacking!

-1:-- Port: a minimalist prepl client for Emacs (Post Bozhidar Batsov)--L0--C0--2026-05-12T06:00:00.000Z

Dave's blog: Remote Linux kernel development with Emacs

I work on developing features and fixing bugs in the Linux kernel in areas specific to IBM Power. I use a number of Emacs’ facilities to get my work done.

Magit

I use Magit extensively with clones of various Git repositories from https://git.kernel.org/. I keep learning new (to me) things about git and Magit and using them. I’ve found it useful to learn how things work with the command line before attempting to use them in Magit.

Compilation

This work being with C source code, I make heavy use of M-x compile. I’ve made my life easier by preloading a couple of items in compile-history. I don’t need this everywhere, just in my Linux trees, so I put all of my Linux repositories under ~/linux, and there I’ve created a .dir-locals.el for directory local variables:

((nil . ((compile-history 
	  . 
	  ("nice make -k ARCH=powerpc CROSS_COMPILE=powerpc64le-linux-gnu- -j `nproc` all compile_commands.json gtags"
	   "nice make -k ARCH=powerpc CROSS_COMPILE=powerpc64le-linux-gnu- -j `nproc` tarzst-pkg"
	   )
	  )
	 )
      )
 )

I do my work on my x86_64 laptop, and cross compile for the powerpc architecture in 64-bit little endian mode. I take advantage of all of the threads available on my laptop. I use nice to make it a bit easier to interactive things while compiling.

The first history item does the big work. I build the all target to build the kernel and modules. I build compile_commands.json to capture the information needed by clangd to use with Eglot. I also keep gtags databases up-to-date, though I should probably drop that since I’m completely using Eglot with clangd at this point.

The second history item creates a .tar.zst file from the kernel and modules, which I transfer to the remote Power partition.

C mode and Eglot

I use c-ts-mode with Eglot. Eglot is integrated with xref.

TRAMP

My test systems are remote, so I need to transfer the kernel and modules over to it. I initially use TRAMP with the scp method to transfer the compressed tar file. If I rebuild and create a new package with the same name, I switch to the rsync method to transfer. This saves several seconds each time.

In both of these cases, I’ve set up keys so I do passwordless authentication.

Non-Emacs things on the remote system

Once I have the tar file on the remote system, there are some non-Emacs things to do. I’m almost certain I can do them in Emacs, as they’re just command line things, but I’m just not used to that and haven’t pushed myself to try it.

  • untar the tarball in / (as root)
  • run dracut to create an init ramdisk
  • optionally remove older kernels and modules
  • run grub2-mkconfig to add the new kernel to the GRUB menu
  • copy the new grub config file to the right place
  • reboot
-1:-- Remote Linux kernel development with Emacs (Post Dave's blog)--L0--C0--2026-05-12T00:00:00.000Z

Thanos Apollo: The Most Emacs Bzr Saga

Since I had no interesting books to read today, nor interesting films to watch, I decided to scavenge for the most intriguing content one can find online. I ended up reading the Linux kernel mailing lists, but those discussions seemed to be 18+, so I settled for the comparatively civil emacs-devel.

For those unfamiliar, emacs-devel is the primary development discussion list for GNU Emacs – where design decisions get made, patches get reviewed, and occasionally where people spend 200 messages arguing about version control software. This is the story of that last one.

2008: “This question is over and decided”

In March 2008, Emacs was migrating from CVS (yes, CVS) to something more “modern”. The two contenders were Git and Bazaar.

  • Git, created by Linus Torvalds for the Linux kernel.
  • Bazaar was a GNU project, maintained by Canonical

A 236-message thread erupted on emacs-devel. People benchmarked both tools. The results were not subtle. Andreas Schwab, one of the core developers, reported his first impression:

My first impression is that bzr is slow, so slow that it is completely unusable. How can it come that a simple bzr log takes more than a minute to even start? Even cvs log is instantaneous in comparison, although it has to request the log from the server.

David Kastrup found it equally puzzling:

I find this surprising: “git log” is pretty much instantaneous, and git recalculates a code piece’s history in the process. In contrast, one has to tell Bazaar when one copies or moves or renames files, so it should have the information available right away.

The actual numbers:

  • git log | head -1 0.012 seconds. The same command with Bazaar took 21.5 seconds.
  • Committing a single-file change: 0.08 seconds with Git, 17 seconds with Bazaar.

The benchmarks kept coming. Stefan Monnier, the head maintainer, set the bar low:

I don’t care if Bzr is slower or faster than Git, but in order to switch to Bzr, we need it to be ‘fast enough’. Currently it is not. At the very least the ‘bzr diff’ should not take more than a couple seconds.

Meanwhile, Jonathan Lange, an actual Bazaar developer from Canonical, was in the thread doing tech support.

His recommended workflow for the initial checkout:

An even better way to do the initial download is this:

$ wget http://bzr.notengoamigos.org/emacs.tar.gz

$ tar xzf emacs.tar.gz

$ bzr init-repo emacs-bzr

$ cd emacs-bzr

$ bzr branch ../emacs trunk

$ cd trunk

$ bzr pull –remember http://bzr.notengoamigos.org/emacs/trunk/

Compare that to git clone!

Someone in the thread finally asked the obvious question:

To the emacs maintainers and decision makers: What more information is required to convince bzr is not the right tool at the present moment?

Richard Stallman’s reply:

This decision is not a decision for the present moment. It is a long term decision. So it would be better to wait a few months while Bzr developers improve it, than to make some other “temporary” decision that would probably be hard to reverse.

And in case anyone missed the point, in a separate message:

This question is over and decided. We will use GNU Bzr, because it is a GNU package.

When someone pointed out that this political decision was “wiping away all technical arguments,” RMS replied:

The rule that GNU packages should support each other helps make the GNU system as a whole work better.

Someone asked the obvious follow-up: “Why can’t we just make Git part of the GNU system?”

RMS:

We could include it in the GNU system, but its developers are not likely to want to make it a GNU package.

To be fair to RMS, there’s a real principle here. If the GNU project doesn’t use its own tools, it sends a message that those tools aren’t good enough, which undermines the whole idea of a self-sufficient free software ecosystem. He’d been making this argument for decades, and it had served the project well in many other cases. The problem wasn’t the principle. The problem was that Bazaar couldn’t live up to it.

The 236-message thread, the benchmarks, the Canonical employee’s workarounds; none of it changed the outcome. The decision was political, and the politics were settled.

2008-2012: The long tail

The rest of the world moved to Git. GitHub launched in 2008 and exploded. Emacs contributors, meanwhile, had to learn Bazaar, a tool they used nowhere else, just to submit patches.

Threads like “Help me unstick my bzr, please” and “Can NOT bzr the emacs repos (may be bzr has a memory leak)” became regular occurrences.

Then in 2012, Canonical laid off the Bazaar development team.

2013

In March 2013, a year after Bazaar’s development ceased, John Wiegley posted what everyone had been wanting to say:

We have often debated the merits of Git vs. Bazaar, and which one the GNU project should use for Emacs development. I think now is an appropriate time to revisit this decision.

My main reason for bringing this up again is that Bazaar development has effectively stalled. There are major bugs which have been in their bug-tracker for years now – bugs affecting Emacs development, such as the ELPA repository – which have been ignored all this time.

So, to Richard as the undisputed Czar of all things Emacs: can we now, pretty please, switch to Git?

200 messages followed.

RMS’s first response:

The maintainer says he is fixing some bugs, and I asked him just yesterday to fix the ELPA branch bug. I’d like to give him a reasonable time to do this.

The bug was 1.5 years old. Dmitry Gutov called it out:

Isn’t this a bit late? The bug is 1.5 years old. Was he not aware of it before?

Then RMS revealed his hand:

I am trying to determine whether Bzr is effectively maintained or not. I’d rather get a Yes answer than a No answer.

That’s a remarkably honest thing to say publicly. He wasn’t hiding his preference. He genuinely believed in the principle of GNU projects supporting each other, and he was hoping reality would cooperate.

Joakim Verona, a longtime Bazaar user and Emacs contributor, described the reality on the ground:

I have done my best to be a constructive user of the tool, and I have had many technical difficulties. When I try to find solutions to the issues I notice the following:

  • The bzr community is very helpful. This is good.
  • There are many well known bugs. There are also many well known patches for these, some of them provided by Emacs developers. They never enter upstream. By “never” I mean years. This is bad.

RMS replied:

I don’t have time to read the Bzr mailing list. Or any development mailing list. The only such list I am on is this one. You might as well tell me to fly to the moon as tell me to read something on the Bzr list.

And when asked whether the users of Bazaar should have a say in whether Bazaar is sufficiently maintained:

When I have to decide whether a maintainer is doing an adequate job or needs to be replaced, I pay attention to whatever relevant information I get. However, to give users “a say” in the decision seems improper, so I don’t do that.

Karl Fogel, a veteran open source developer (author of Producing Open Source Software and one of the original Subversion developers), delivered the sharpest critique in the thread:

Well, really, you don’t have time to pay close enough attention to Bzr development to competently decide whether it’s still a good choice for Emacs. That’s fine – no one has time to do every important thing, and you do many other important things.

But then why do you think you still have the time & mental bandwidth to make this decision well? Why not delegate it to the Emacs maintainers on the grounds that you no longer have time to do a good job of this evaluation?

He pointed out that asking one person about one bug is not a proxy for project health, and that others in the thread had already done more thorough research than RMS could, given his time constraints.

RMS’s reply:

Because more than Emacs is at stake here.

One line, but it’s the core of his worldview. If the flagship GNU project abandons a GNU tool, what signal does that send to every other GNU package? He wasn’t wrong about the stakes. He was wrong about the tool.

Karl pushed once more:

You should either devote enough time to evaluating Bzr’s maintenance state to get a reliable answer, or delegate to someone who can do so. Instead, you’re asking the maintainers to rely on your investigation… yet you clearly don’t have time to do a good job. This is a poor use of everyone’s time.

RMS:

I already have a plan for how to proceed on this, and I am doing it.

No details. No timeline. No delegation. Trust me.

Meanwhile, Stefan Monnier, posted exactly one substantive message in the entire 200-message thread:

Just like I didn’t fight Richard’s choice of Bazaar, I don’t care very much whether we keep using Bazaar or we change to Git, Monotone, Darcs, Mercurial, OpenCM, Fossil, younameit.

The only thing I care for now is to move away from Bazaar for the ’elpa’ branch because Bazaar can’t handle it properly.

Leo Liu summarized what everyone was thinking:

Most GNU projects aren’t using BZR as you might be aware.

While helping BZR fixing bugs might be a gain for BZR, it is a loss as a whole for GNU. Volunteers spend their spare time on GNU projects and if 20% of that time is taken up by wrestling with BZR, it becomes costly to the point discouraging people from joining.

For the greater good of GNU, move off BZR seems like the only sound choice.

The thread ended without a clear resolution. RMS had a plan. He was working on it. The 200 messages didn’t produce a decision, but they did make the community’s position unmistakable.

2013: The ELPA branch breaks

Later that year, Stefan made the practical move that set the stage for everything that followed. The ELPA branch was broken on Bazaar, a bug that crashed on checkout, with no one left to fix it. Stefan moved it to Git, and his announcement showed exactly the kind of careful leadership that had kept Emacs development running through all of this:

I’m not terribly happy about this change, since it means we’ll be using two different tools (Git for ’elpa’ and Bzr for ’trunk’), but I really see no other way out.

I don’t want this to be a discussion about the merits/pitfalls of Git vs Bzr, and this is not an occasion to discuss the use of Git for the ’trunk’ either.

He knew exactly what everyone was thinking “if Git is good enough for ELPA, why not for trunk?” and he headed it off. One problem at a time.

2014: ESR pushes the button

By August 2014, Eric S. Raymond had the conversion scripts ready.

He’d been working on it quietly:

You haven’t heard much about it because the hard work is all done. I have the scripts ready to go and need only about eight hours’ notice before pushing the button.

The actual migration happened in November 2014. On November 13th, ESR posted a six-word message:

Commits are open. Have at it.

Which some even described as heroic.

Six years of debate, 236 messages in the 2008 thread, 200 messages in the 2013 thread, Stefan’s years of quiet maintenance, countless “help me unstick my bzr” pleas, one dead version control system, and it ended with six words.

The aftermath

The days following the migration were educational. Half the core contributors had never used Git:

  • This Is The Git Help Mailing List
  • “git pull fails with merge conflicts. How can this possibly happen?”
  • “A simple git workflow for the rest of us”
  • “need help adjusting workflow to git”
  • “Good book on Git”
  • “Obscure error/warning/information message from git pull” (124 messages)

These were people who’d been developing one of the most important text editors in the world for years, asking basic Git questions, because they’d been stuck on Bazaar while the rest of the world moved on.

What a bzr saga! Anyway, better than any film I could have watched tonight.

-1:-- The Most Emacs Bzr Saga (Post Thanos Apollo)--L0--C0--2026-05-11T21:00:00.000Z

Charles Choi: Enhancing Elisp Development with Context Menus

As celebrated as Emacs is for its programmability, I find the actual process of developing Emacs Lisp (Elisp) to be quite underwhelming. Developing in Elisp has meant learning its libraries and idioms, which is to be expected. What I really don’t care for though are the arcane keybindings associated with doing basic things like evaluating, navigating (Xref), and debugging (especially debugging). While I’ve already committed to muscle memory most of said keybindings, I’d argue that having a mouse-based “point and click” interface is beneficial for both novice and experienced Elisp developers alike, as it lets one focus on the code and not on recalling the right key incantation all the time.

The addition of context-menu-mode in Emacs 28 has provided the opportunity to build a mouse-based UI for Elisp development and I’m happy to announce the availability of one in the latest v1.3.0 update to Anju, now on MELPA.

To get an idea of what’s available in the v1.3.0 update, here’s a screenshot of the context menu when normally editing an Elisp file where the point is on the symbol foo.

img

If foo is instrumented for debugging and run, the context menu is adjusted to provide Edebug commands as shown below.

img

The context menu enhancements provided by Anju take full advantage of built-in functions that identify context at point. Is the point on a symbol? In a function? In an ERT test? On a lambda? The menu items added by Anju take these factors into account to provide a relevant menu offering.

Users can read more about Anju’s context menu enhancements for Elisp development at Emacs Lisp Context Menu (Anju User Guide).

Some backstory with Edebug

Back in 2024, I did a deep dive into Edebug so as to give a presentation on it at the EmacsSF meetup. In doing so, I realized that all the core features for having an Elisp IDE were there, but no good UI to present it. I set upon prototyping one using Transient, with decidedly mixed results due to both Edebug and Transient fighting each other over window management.

A later Edebug UI prototype using the toolbar was attempted but it also had its issues, particularly with layout (or lack thereof) and toolbar-specific bugs in macOS. But a benefit of using the toolbar was that its UI interactions did not interfere with window management. The context menu also shares this benefit.

Closing Thoughts

The context menu has markedly improved my developer experience with Elisp, as I find myself using it more than typing out keybindings. Even with keybindings, I’ll use the Casual Elisp Transient to accomplish most Elisp interactions that don’t require Edebug.

That said, I’m not here to eschew keybindings. I still use them, when convenient. But in many circumstances they are not. The context menu can provide an easier way to achieve the same thing. Isn’t that a good thing?

-1:-- Enhancing Elisp Development with Context Menus (Post Charles Choi)--L0--C0--2026-05-11T18:00:00.000Z

Irreal: ICanHazShortcut 2.0

I’ve been using ICanHazShortcut for years. I originally started using it to have an easy way to switch to Emacs from anywhere in my system. Eventually, I added Safari and HomeKit to the list of apps I can invoke with a simple keypress but most of my ICanHazShortcut shortcuts are Emacs related. For example, I have F9 mapped to Emacs capture so that I can invoke any Org capture template from anywhere on my system. That’s really handy and I use it several times a day. I also have a shortcut to invoke Emacs Everywhere so that I can escape into the comfort of Emacs when entering data in some other app.

Today (Sunday, as I write this) I received a notification that a new version of ICanHazShortcut was available. It’s completely rewritten in Swift from Basic and has some new capabilities. You can read about them at the above link. For me, not much has changed. The new version continues doing what ICanHazShortcut has always done.

ICanHazShortcut is a minimal app that simply provides a shortcut for any command that you can specify in the terminal. There are plenty of more full featured key mappers available that may be better for more complicated situations but I find ICanHazShortcut perfect. It’s light weight and easy to configure. I almost never mess with ICanHazShortcut’s configuration. The last time I changed it—to add HomeKit, I think—was years ago. It truly is a set it and forget it app.

If you want a simple app for invoking Emacs—or anything else—in various ways, take a look at ICanHazShortcut; it’s worked very well for me.

-1:-- ICanHazShortcut 2.0 (Post Irreal)--L0--C0--2026-05-11T14:27:26.000Z

Sacha Chua: 2026-05-11 Emacs news

People are getting Emacs 31 ready for release. Looking forward to that! See emacs/etc/NEWS.31 for details.

Lots of posts for the Emacs Carnival theme of "May I recommend…", yay!

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 e-mail me at sacha@sachachua.com.

-1:-- 2026-05-11 Emacs news (Post Sacha Chua)--L0--C0--2026-05-11T13:00:59.000Z

James Cherti: A Technical Guide to Compiling Emacs for Performance on Linux and Unix systems

Most Linux distributions ship generic binaries compiled to run safely on a vast array of older hardware configurations. While this ensures broad compatibility, it sacrifices the speed that comes from using the specific, modern instruction sets of your processor. Building Emacs directly from source allows instructing the compiler to generate machine code targeted at your CPU architecture, resulting in a faster and more efficient runtime environment.

Before we dive in, please consider sharing this article on your website, blog, Mastodon, Reddit, X, Linkedin, or other social media platforms. Sharing it will help other Emacs users discover how to properly build Emacs for performance.

Beyond raw hardware optimization, building from source enables dropping decades of legacy compatibility layers and embracing modern desktop technologies. For example, Wayland users can configure the build to bypass old X11 display protocols in favor of a Wayland environment, ensuring smoother rendering and better system integration.

Additionally, this article details how to optimize the internal native Lisp compiler, which transforms Lisp packages into machine code to ensure that every Emacs package in your configuration operates at its maximum potential speed.

Here is the step-by-step process for building a highly optimized Emacs binary and packages.

Installing dependencies

Arch Linux

On Arch Linux, the cleanest and most native method to resolve build dependencies is to use the official Emacs PKGBUILD, which automatically read the official dependency list and install them:

mkdir -p ~/emacs-deps
cd ~/emacs-deps
wget https://gitlab.archlinux.org/archlinux/packaging/packages/emacs/-/raw/main/PKGBUILD
makepkg --syncdeps --nobuild

NOTE: Once makepkg finishes installing the dependencies, you can safely delete the ~/emacs-deps directory.

Debian, Mint and Ubuntu

On Debian-based systems, the most efficient method to gather dependencies is to use the package manager to automatically fetch them based on the distribution’s source package. You must first ensure that source repositories are enabled:

  • Open /etc/apt/sources.list with root privileges in your text editor.
  • Find the lines starting with deb-src (Read: “sources.list format” on Debian Wiki) and uncomment them by removing the # at the beginning of the line.
  • Update your package lists and download the install Emacs dependencies:
sudo apt update
sudo apt build-dep emacs

Other Linux Distributions (Generic)

If you are using a distribution not listed above, you will need to use your distribution’s specific package manager to install the required development libraries. Look for packages that include the library headers, typically suffixed with -dev or -devel.

Here is the master list of upstream library names required to compile this specific Wayland and Native-Comp optimized build:

  • Core Build Tools: gcc, make, autoconf, automake, pkg-config (or pkgconf), git, texinfo
  • Native Compilation Engine: libgccjit (Ensure this matches your GCC version)
  • System and Core Libraries: glib2, gnutls, zlib, ncurses, sqlite3, tree-sitter, gmp
  • Graphics and Wayland Toolkit (PGTK): gtk3, cairo, harfbuzz, pango, dbus
  • Image Formats: libjpeg (or libjpeg-turbo), libpng, libtiff, giflib, libwebp, librsvg2, lcms2
  • Fonts and Text Shaping: fontconfig, freetype2, libotf, m17n-lib, libxml2

Optimizing the Native Lisp Compiler

Fine-Tuning Native Compilation

Before building Emacs with native compilation support, we will optimize how Emacs transforms Lisp packages into machine code. This is managed via the native-comp-compiler-options variable. While the main Emacs build uses your global CFLAGS, this variable specifically instructs libgccjit on how to handle every .el file it encounters.

Add the following to your early-init.el file:

;; Display the architecture using:
;;   gcc -march=native -Q --help=target | grep march
;;
;; The above command asks the compiler to resolve native for your current CPU
;; and display the resulting target. For example, if the output shows
;; -march=skylake, you know that skylake is the identifier you should pass to
;; -mtune and -march.
(setq my-cpu-architecture "CHANGE_THIS_TO_YOUR_ARCHITECTURE")

;; `native-comp-compiler-options' specifies flags passed directly to the C
;; compiler (for example, GCC) when compiling the Lisp-to-C output
;; produced by the native compilation process. These flags affect code
;; generation, optimization, and debugging information.
(setq native-comp-compiler-options `(;; The most meaningful optimizations:
                                     "-O2"
                                     ,(format "-mtune=%s" my-cpu-architecture)
                                     ,(format "-march=%s" my-cpu-architecture)
                                     ;; Reduce .eln size and compilation
                                     ;; overhead.
                                     "-g0"
                                     ;; Good defensive choice for Emacs
                                     ;; stability.
                                     "-fno-omit-frame-pointer"
                                     "-fno-finite-math-only"))

(setq native-comp-driver-options '(;; -Wl,-z,pack-relative-relocs compresses
                                   ;; relocation tables to reduce file size and
                                   ;; slightly improve load times.
                                   "-Wl,-z,pack-relative-relocs"
                                   ;; -Wl,-O2 applies standard linker-level
                                   ;; optimizations (like string merging) to the
                                   ;; generated shared object.
                                   "-Wl,-O2"
                                   ;; -Wl,--as-needed prevents the linker from
                                   ;; recording dependencies on libraries that
                                   ;; are not actually used by the code.
                                   "-Wl,--as-needed"))

IMPORTANT: Change CHANGE_THIS_TO_YOUR_ARCHITECTURE to your specific architecture. Run the following command to display the CPU architecture:

gcc -march=native -Q --help=target | grep march

The above command asks the compiler to resolve native for your current CPU and display the resulting target. For example, if the output shows -march=skylake, then replace CHANGE_THIS_TO_YOUR_ARCHITECTURE with skylake.

(If you prefer automatic CPU architecture detection, refer to the comments section below. I shared a function that detects the CPU architecture using gcc and adds it to the configuration.)

NOTE: Avoid adding -mtune=native and/or -march=native to the native-comp-compiler-options variable. While these flags work in global CFLAGS, libgccjit, the library responsible for native compilation, often fails to resolve the native keyword correctly. This happens because the JIT interface does not always trigger the same host-probing logic as the standalone GCC driver.

The rationale behind the selection of these flags is as follows

  • The choice of -O2 is an intentional balance. While -O3 may provide small performance gains in some workloads, it can also increase binary size and occasionally reduce responsiveness. -Ofast is generally discouraged because it enables aggressive floating-point optimizations.
  • Using -g0 disables the generation of debug symbols for .eln files, which reduces their size on disk and speeds up the compilation process itself.
  • -fno-omit-frame-pointer The Emacs developers recommend using this flag to disable omit-frame-pointer. Although enabling omit-frame-pointer frees up a general-purpose CPU register, it does not yield significant performance gains on modern architectures and can lead to bugs that are difficult to debug. According to Eli Zaretskii, an Emacs developer: “See bug#76180. This is in the context of the igc branch, where omit-frame-pointer is particularly troublesome, though it also causes problems in other situations. For further details, see etc/DEBUG in the Emacs source tree.”
  • The -fno-finite-math-only flag prevents the compiler from assuming that floating-point operations never produce NaN or infinity values. This flag is mostly defensive because GCC does not enable -ffinite-math-only at -O2 by default, but it can help avoid unsafe assumptions if additional aggressive optimization flags are introduced later.

For users looking to ensure a fully optimized environment, the compile-angel package is a valuable addition to the native compilation workflow. Integrating compile-angel guarantees that every .el file in your load path, including your own configuration and manually managed .el files, is properly byte and natively compiled. This ensures a consistent performance boost across the entire editor.

Purging the Native Cache to Force JIT Recompilation

After modifying the native-comp-compiler-options and/or native-comp-driver-options variables, you must force Emacs to rebuild your packages. Ensure Emacs is closed and delete all existing .eln binaries using the following command:

find ~/.emacs.d/ -name '*.eln' -delete

Because Emacs uses a deferred compilation engine (Native JIT compiler), you do not need to manually trigger a build script. Simply launch Emacs and begin your normal workflow. As Emacs loads your packages and detects the missing .eln files, it will spin up background threads to recompile them using your new optimization flags.

Compiling Emacs for Performance

Step 1: Cloning and Preparing the Source

To build Emacs, you must first obtain the source code from the official mirror and switch to a stable release branch:

git clone https://github.com/emacs-mirror/emacs
cd emacs
git checkout "emacs-30.2"

NOTE: The official Savannah Git repository at https://git.savannah.gnu.org/git/emacs.git can occasionally be slow or unreliable, so this guide uses the official GitHub mirror instead.

We target a specific release tag like emacs-30.2 (If you desire to install another version, you can display tags using the git tag command) to ensure a stable foundation. Building from a tagged release, rather than the bleeding-edge development branch like the master branch, minimizes the risk of build failures or experimental regressions that could impact your daily productivity.

Standard cleanup is often insufficient when switching branches or recovering from a failed build. Execute the following commands to ensure a pristine environment where no residual artifacts can interfere with the new build:

git reset --hard HEAD
git clean -f -d -x
rm -fr .git/hooks/*

(Executing these commands acts as the ultimate factory reset for your repository, which is important when switching between major Emacs versions. Emacs has a highly complex build process where the C core compiles its own Lisp files; if leftover artifacts from a previous configuration, such as cached object files, old Makefiles, or stale byte-compiled .elc scripts, git hooks, are left behind, they can silently contaminate the new build and cause segmentation faults or compile-time errors. Together, these commands guarantee a pristine, predictable environment.)

Once inside the repository, all subsequent configuration and compilation commands are executed from this directory.

Step 2: Generating the Configuration Script

Emacs uses the Autotools build system, which requires generating the final configuration script before it can be used:

./autogen.sh

This shell script reads the developer configuration files provided in the repository and generates the final ./configure script. It sets up the necessary infrastructure to inspect your specific environment, locate system libraries, and prepare the Makefile.

Step 3: Setting Compiler and Linker Flags

To enhance runtime performance, we must export specific variables that instruct the C compiler and linker to optimize the resulting binary for the host CPU:

export CFLAGS="-O2 -pipe -march=native -mtune=native -fno-omit-frame-pointer -fno-plt -flto=auto"
export LDFLAGS="-Wl,-O2 -Wl,-z,now -Wl,-z,relro -Wl,--sort-common -Wl,--as-needed -Wl,-z,pack-relative-relocs -flto=auto -O2"

The CFLAGS variable tells the compiler to apply safe, general-purpose optimizations (-O2), optimize instruction scheduling for the specific CPU compiling the code (-march=native and -mtune=native), store the metadata necessary for the linker to later perform cross-module optimization (-flto=auto), disable omit-frame-pointer (-fno-omit-frame-pointer), use memory pipes instead of temporary files to speed up the build (-pipe), and remove indirect PLT calls to external functions, improving runtime call efficiency at the cost of slightly higher startup and dynamic loading overhead (-fno-plt).

The LDFLAGS variable instructs the linker to apply additional optimization passes to the final executable (-Wl,-O2), group common symbols to reduce duplicate storage (-Wl,--sort-common), avoid linking unused shared libraries (-Wl,--as-needed), reduces binary size by performing a global analysis to inline functions and remove dead code across the entire program (-flto=auto), compress relative relocations to reduce relocation overhead and binary size (-Wl,-z,pack-relative-relocs), resolve all dynamic symbols at startup, trading slightly slower launch time for faster, more consistent runtime execution (-Wl,-z,now -Wl,-z,relro). Together, these flags help produce a smaller, more memory-efficient executable with improved startup and runtime performance.

NOTE 1: To successfully build Emacs using Link-Time Optimization (LTO) -flto, It is recommended to maintain a consistent optimization level, such as -O2, across both the compilation (CFLAGS) and linking stages (LDFLAGS). When enabling -flto=auto in your CFLAGS, the compiler emits GIMPLE intermediate representation; the actual transformation into an optimized executable is deferred until the linking phase, where the GCC driver re-invokes internal optimization passes. While modern GCC versions can often infer the correct heuristics from metadata embedded within the object files if a link-time flag is missing, explicitly including -O2 in your LDFLAGS is recommended for a predictable, deterministic build. This practice ensures that the whole-program analysis phase executes the exact same optimization level as the initial compilation. (Source: “To use the link-time optimizer, -flto and optimization options should be specified at compile time and during the final link. It is recommended that you compile all the files participating in the same link with the same options and also specify those options at link time…”)

NOTE 2: You must ensure CC are exported to the exact gcc version that matches your libgccjit version. For example: export CC="/usr/bin/gcc-11".

Step 4: Configuring the Build

We run the configure script to select exactly which features to include.

For X11 users:

./configure \
  --with-x \
  --with-x-toolkit=gtk3 \
  --without-toolkit-scroll-bars \
  --with-cairo \
  --without-xft \
  --with-harfbuzz \
  --without-libotf \
  --with-gnutls \
  --without-xdbe \
  --without-xim \
  --without-gpm \
  --disable-gc-mark-trace \
  --with-gsettings \
  --with-modules \
  --with-threads \
  --with-libgmp \
  --with-xml2 \
  --with-tree-sitter \
  --with-zlib \
  --without-included-regex \
  --with-native-compilation \
  --with-file-notification=inotify \
  --without-compress-install

For Wayland users:

./configure \
  --without-x \
  --with-pgtk \
  --with-toolkit-scroll-bars \
  --with-cairo \
  --without-xft \
  --with-harfbuzz \
  --without-libotf \
  --with-gnutls \
  --without-xdbe \
  --without-xim \
  --without-gpm \
  --disable-gc-mark-trace \
  --with-gsettings \
  --with-modules \
  --with-threads \
  --with-libgmp \
  --with-xml2 \
  --with-tree-sitter \
  --with-zlib \
  --without-included-regex \
  --with-native-compilation \
  --with-file-notification=inotify \
  --without-compress-install

The rationale behind the selection of these flags is as follows

  • --disable-gc-mark-trace: Disable the GC mark trace buffer for about 5% better garbage collection performance. It removes debugging code from the garbage collector marking phase. This provides a reduction in overhead during garbage collection cycles, leading to a more responsive experience during memory-intensive tasks.
  • --with-native-compilation Enable native compilation. (I omitted the aot flag to instruct the build system to skip compiling the built-in Lisp files during the make step. Instead, Emacs defers this work until runtime, where it will use the optimizations in native-comp-compiler-options and native-comp-driver-options while compiling all .el files the first time Emacs is launched.)
  • --with-cairo and --with-harfbuzz enable modern text rendering.
  • --without-compress-install By default, Emacs compresses its installed Lisp files to save disk space. Using this flag keeps the files uncompressed. The benefit is faster load times when Emacs needs to read these files from disk, as it skips the decompression step entirely. (On modern SSDs, loading compressed .el.gz files generally takes a bit more time than loading uncompressed files. While compression definitely saved time on older spinning hard drives by reducing I/O waits, modern solid-state drives can read uncompressed data at gigabytes per second. That being said, the actual performance gain of using uncompressed files is often negligible in practice. This is especially true if you are compiling all your .el files, because Emacs prefers to load the compiled byte-code .elc or native code .eln)
  • --without-xft Disable xft because modern Emacs rendering no longer needs it. Modern GTK builds of Emacs use Cairo + HarfBuzz handle rendering.
  • --without-included-regex Makes Emacs use the system libc regex implementation. On contemporary Linux systems using glibc, the system regex engine is usually better optimized and maintained than Emacs’s bundled GNU regex implementation.
  • --with-libgmp Enables GMP, the GNU Multiple Precision Arithmetic Library, an optimized engine Emacs relies on to calculate arbitrary-precision integers (bignums) at bare-metal speeds. Modern Emacs workflows constantly process massive numbers in the background. If you disable this flag or fail to install the system library, Emacs is forced to fall back on mini-gmp, a generic, software-only C implementation designed strictly for portability rather than speed.
  • --without-xim: Disable XIM, a legacy X Input Method protocol used primarily for typing complex languages (like Chinese, Japanese, or Korean) on old X11 systems. If you use GTK3/Wayland, modern input methods handle this instead. Disabling this is recommended for Wayland/PGTK users as it removes unnecessary X11-specific code.
  • --with-file-notification=inotify Guarantees that the build will use the Linux kernel’s efficient event-watching API rather than falling back to slow, resource-heavy polling if the detection fails.
  • --with-gsettings Enable communication with the GTK configuration storage system. This allows inheriting system-wide preferences for themes, fonts, antialiasing hints…
  • --without-libotf: Disables the legacy OpenType Font library. This is recommended for modern builds that use HarfBuzz (--with-harfbuzz), as HarfBuzz handles text shaping more efficiently. Disabling this library reduces binary size without sacrificing font quality in modern desktop environments.
  • --with-gnutls: Enables secure network communication. This is required for secure package installation from MELPA/ELPA and for browsing HTTPS websites via EWW.
  • --without-xdbe: Disables the X11 Double Buffer Extension. This protocol is redundant for modern builds because both the PGTK (Wayland) and GTK3 (X11) layers handle window buffering internally. Disabling it simplifies the binary and ensures Emacs uses modern rendering paths.
  • --without-gpm Disable General Purpose Mouse (GPM), a background service that provides mouse support for the Linux console (the text-only TTY you see before logging into a graphical desktop). Unless you plan to use Emacs in a bare-metal Linux console (outside of a terminal emulator like Alacritty, Foot, or GNOME Terminal), GPM is unnecessary. Modern terminal emulators use their own internal protocols for mouse interaction that do not rely on the GPM daemon.

Additional flags to pass to ./configure

If your workflow is primarily text-based, you can significantly reduce the number of external libraries linked to your binary. However, each omission comes with a specific trade-off:

  • --without-sound Disables support for audio notifications. You will not hear the audible system bell or sound cues from productivity packages like Pomodoro timers or chat clients.
  • --without-libsystemd Disables the ability for Emacs to communicate with systemd. You cannot use advanced systemd service features, such as Type=notify, which allows systemd to know exactly when the Emacs daemon is fully loaded and ready.
  • --without-dbus: Disables D-Bus integration in Emacs. This produces a slightly leaner build, but removes integration with desktop services that rely on D-Bus. Depending on the desktop environment and enabled packages, this can affect desktop notifications, interaction with services such as GNOME Keyring, file manager integration, power and network state notifications, and various portal-based desktop features. It is generally safe on minimal Emacs GUI builds or terminal-only setups, but many modern Linux desktop environments expect D-Bus support.
  • --without-gconf Disables support for GConf. This is a deprecated GNOME configuration system that was replaced by GSettings. Disabling it ensures your build is not carrying legacy, obsolete desktop integrations.
  • --without-sqlite3 Disables the built-in SQLite engine. This breaks modern packages that rely on a local database for performance, such as org-roam or certain mail indexers.
  • --without-m17n-flt Disables the m17n library for complex text layout. While fine for English-only workflows, this will cause rendering issues (incorrect character joining or positioning) for complex scripts like Indic or Thai.
  • --without-selinux Disables Security-Enhanced Linux support. On systems where SELinux is active, Emacs will be unable to preserve or manage SELinux security contexts when creating or copying files, potentially leading to permission issues or security policy violations.
  • --without-libsmack Disables Smack security support. Similar to SELinux, if your Linux distribution uses the Smack kernel security module, disabling this prevents Emacs from managing those specific security contexts on files.
  • --disable-build-details: Omits build metadata, such as your machine’s hostname and the compilation timestamp, from the final executable. While this doesn’t provides performance or startup speed benefits, it ensures a “reproducible build” and prevents your personal system details from leaking if you share your compiled binary.
  • --without-gif, --without-jpeg, --without-png, --without-rsvg, --without-tiff, --without-xpm, --without-webp Disabling these prevents Emacs from linking against heavy image processing libraries. Emacs will be unable to render these image formats natively. This breaks functionality for image-heavy modes, such as image-mode, viewing PDFs via pdf-tools, or displaying mathematical LaTeX previews.
  • --without-imagemagick Prevent Emacs from using this large dependency for complex image transformations. You lose the ability to perform advanced image manipulation (like dynamic resizing or rotation of certain formats) within Emacs buffers.
  • --without-lcms2 Remove the Little CMS color management layer. Images may appear with slightly incorrect colors on high-quality displays, as Emacs will ignore ICC color profiles embedded in files.
  • --without-xinput2: Disables the modern X11 input extension. Warning: If you are building for X11, disabling this will break pixel-precision smooth scrolling for trackpads and mouse wheels, forcing Emacs to use choppy line-by-line scrolling. This flag does nothing for Wayland/PGTK builds and offers no performance benefits.
  • --disable-acl: Disables support for Access Control Lists. Disabling this reduces the number of system calls Emacs performs during file operations. This is a good choice for single-user systems where standard Unix permissions are sufficient.
  • --disable-xattr: Disables support for Extended File Attributes. Only keep this enabled if you rely on SELinux or filesystem-level file tagging.
  • --without-kerberos --without-pop --without-kerberos5 --without-hesiod --without-mail-unlink: These flags disable support for ancient mail retrieval methods, directory services, and local mail spool manipulation. Because modern Emacs mail setups rely on external synchronization, disabling these ensures the build script does not waste time searching for legacy network libraries and keeps the binary entirely free of dead mail code.

Step 5: Compiling the Source Code

With the configuration complete, the next step is to compile the C source files and the core Emacs Lisp files:

make -j "$(nproc)" -l "$(nproc --ignore=1)"
  • -j $(nproc): This sets the maximum number of concurrent jobs to the number of CPU cores. Make will attempt to run up to the the number of CPU cores compilation commands in parallel. This is an upper bound; actual concurrency may be lower depending on dependencies and system load.
  • -l $(nproc --ignore=1): This sets a load average limit. $(nproc --ignore=1) returns the number of available CPU cores minus 1. Example: on an 8-core system, this evaluates to 7. So effectively, -l 7 means: do not start new jobs if system load average is 7 or higher. Make uses system load average (typically 1-minute load average) as a throttling mechanism.

On a low-load system, Make may run close to 48 jobs in parallel. Under high CPU pressure, Make will throttle and pause scheduling new jobs until load decreases.

(Related article: Similar to make -j command above for Emacs compilation, read “Enabling Emacs native compilation and dynamically adjusting the number of Elisp files compiled in parallel“)

Step 6: Installing the Stripped Binary

The final step is to copy the compiled binary and its associated files to their proper locations on your file system.

sudo make install-strip

While the standard make install simply copies the compiled files, make install-strip performs an additional optimization. It strips debugging symbols from the final executable. Removing these symbols reduces reduces binary size on disk.

Verifying Emacs Build Features

After successfully compiling Emacs from source, execute the resulting Emacs binary.

Once the editor is running, it is good practice to verify that your desired features, such as native JSON parsing or tree-sitter support, were correctly detected and linked during the build process.

You can verify this by inspecting the system-configuration-features variable. To view its contents, type M-x describe-variable RET system-configuration-features RET, which will output a string detailing the exact libraries and features baked into your current executable.

Optional: Risky Emacs Optimizations

Risky Optimization: Replacing -O2 with -O3

NOTE: The Emacs developers strongly recommend against using -O3, -Os, and -fsanitize=undefined for ordinary production builds, stating that these flags are known to sometimes cause unpredictable problems with the generated code. (Source: The INSTALL file in the Emacs source tree.) That said, I have compiled Emacs using -O3 and have not experienced any issues.

Here is how to apply this optimization:

  • Compiler configuration: Replace the -O2 flag with -O3 in your CFLAGS. (Avoid substituting -Wl,-O2 with -Wl,-O3 in your LDFLAGS, as the underlying GNU ld documents optimization levels up to -O2 for linker optimizations.)
  • Linker configuration: Replace the -O2 flag with -O3 in LDFLAGS.
  • Emacs configuration: Replace -O2 flag with -O3 in the native-comp-compiler-options variable.

The theoretical benefits of -O3:

  • Aggressive function Inlining: Function inlining speeds up execution by pasting a function’s code directly where it is called, eliminating the overhead of jumping to a different memory address.
  • Loop Unrolling: Loop unrolling is a compiler optimization that copies parts of a loop multiple times so the program does not need to repeatedly check conditions like i < 10 as often. This reduces repeated checks and jumps, allowing the CPU to spend more time performing useful work instead of constantly deciding whether to continue the loop. This creates longer uninterrupted sections of code, which modern processors can execute more efficiently by processing several independent operations in parallel at the same time.
  • Faster Buffer Processing (Vectorization/SIMD): For heavy text searching, such as complex regular expression matching or byte-level buffer manipulation, -O3 may allow the compiler to use special CPU instructions that operate on many bytes of data at once instead of processing each byte individually. For example, instead of comparing one character at a time, the CPU may compare 16, 32, or more characters in a single operation, which can improve performance in some workloads.

The tangible risks of -O3:

  • Instruction Cache Bloat: Aggressive inlining copies large amounts of code directly into other functions, which can significantly increase the size of the final executable.
  • Exposing Undefined Behavior: -O3 enables more aggressive optimizations that assume the C source code fully follows the rules of the C standard. In large and old codebases like Emacs, some code may accidentally rely on behavior that is technically invalid or undefined. When combined with Link-Time Optimization (LTO), the compiler can optimize across multiple source files and make transformations that expose these hidden issues, potentially causing random crashes, UI freezes, or unstable behavior.
  • Mangled Stack Traces: -O3 aggressively rearranges and simplifies code to improve performance. Functions may be merged, variables may disappear entirely, and instructions may execute in a very different order than they appear in the original source code. If Emacs crashes, debugging tools such as gdb may produce stack traces that no longer clearly match the original program structure, making debugging substantially more difficult.

Using -O3 is an experimental optimization. If you experience out-of-memory build failures, random micro-stutters, UI freezing, or crashes, revert to a standard -O2 build with or without LTO.

Conclusion

Compiling Emacs from source and bypassing generic Emacs distribution binaries strips away decades of legacy compatibility layers and align the Emacs’ execution directly with your specific hardware architecture.

Remember to trigger a fresh recompilation whenever you update core system toolchains, such as GCC or your graphical compositor, to maintain binary compatibility and performance integrity.

-1:-- A Technical Guide to Compiling Emacs for Performance on Linux and Unix systems (Post James Cherti)--L0--C0--2026-05-11T11:52:16.000Z

Irreal: Personal Keybindings

Marcin Borkowski (mbork) has an interesting post on the describe-personal-keybindings command. The idea is that the command lists the keybindings that you have set in your configuration. It’s convenient, mbork says, for checking that new Emacs releases haven’t stolen one of your bindings. It’s also interesting to see what bindings you’ve added and what, if anything, they’ve replaced.

But there’s a catch. In order for a personal keybinding to show up, it must have been set with the bind-key macro. That’s a problem for those of us who are long term users. Those who use use-package exclusively have no problem since the :bind command uses bind-key automatically but bindings set with, say, define-key will not appear in the describe-personal-keybindings output.

That’s inspired mbork to refactor his init.el to use use-pacjkage and for stand-alone bindings, the bind-key macro.

The minions are insisting that I mention what they consider the best part of mbork’s post. That, of course, concerned dark mode. Mbork begins his post by mentioning a Web app that provides a Web based cheat sheet of Emacs commands. Mbork says it’s a cool command but not for him because

if I were to create something like that, it would run in Emacs and not in the browser, it would definitely mention transpose-.* commands, and it would never be dark-mode-only;-).

The minions haven’t been causing much trouble lately so I thought it only fair to indulge their desire to get mbork’s dislike of dark mode on the record.

-1:-- Personal Keybindings (Post Irreal)--L0--C0--2026-05-10T14:52:57.000Z

Einar Mostad: Speed improvement hack for dired with EWW

I have used EWW in Emacs for some of my browsing for a while and it does the job very well unless browsing single page applications or other sites that do not send HTML unless you run JavaScript. Thank you Lars Magne Ingebrigtsen for making EWW! Hitting R filters out all the noise for a really pleasant reading experience. It is good to browse within Emacs with no context switching in a keyboard-driven way.

(Apropos they joys of context switching: When I am a bit tired, I use Emacs keybindings everywhere. Tap-to-click is naturally off on my laptops to prevent insanity. I am often able to "help" my students a lot within just a few seconds of random keybindings and clicking everywhere on their laptops. It is really good for students to learn patience and tolerance towards people unable to handle computers. They need that for their user support class and future work in the IT industry.)

When Joshua Blaise wrote about his eww setup and use, I read it with interest and stole most of his ideas for my own config. The important one for this little hack is that I set up URLs with endings like .mp3, .mp4, .m4v, .mkv etc to launch in mpv when browsing to them. This makes watching videos and listening to audio content easy with EWW. EWW is also good for browsing local files by hitting W with point on a file in dired.

In dired, I usually launch external programs for photo editing, media playback etc by pressing & with point on a file name. This brings up the completing-read interface in the minibuffer which asks me if I would like to use dired's guess as to which program to use (which I have set to guess xdg-open first) or something else. I press return and then mpv, gimp, darktable or whatever launches with the file.

I had an html file in my downloads folder which I launched with W to read in EWW. I then, by mistake, hit W when on a .mp3 file, and it launched in mpv. Since W launches the file in EWW and EWW was configured to open .mp3 files in mpv, it did that without asking me which program to use. It is faster to hit W than to hit & RET, or in worst case write a program name and RET. So now I launch media files with W in dired in stead of using &. It speeds things up a bit.

(While writing this, I also remembered that I have functions for playing enclosure links and links in elfeed through mpv that I might replace or improve by shuffling the links to EWW or einar-browse-url-mpv. I wrote my configuration for elfeed very early in my Emacs journey, without really understanding any of it, by copying snippets from the Emacs wiki, blogs and Reddit so it is high time to look at it again anyway. I can probably simplify it.)

Here are the relevant parts of my configuration for EWW to get this working:

(defun einar-browse-url-mpv (url &rest _args)
  "Opens URL in mpv."
  (start-process "mpv" nil "mpv" url))

(use-package eww
  :config
  (setopt browse-url-handlers
          '(("\\(youtube\\.com\\|youtu\\.be\\|vimeo\\.com\\|twitch\\.tv\\)" . einar-browse-url-mpv)
            ("\\.mp3$" . einar-browse-url-mpv)
            ("\\.mp4$" . einar-browse-url-mpv)
            ("\\.webp$" . einar-browse-url-mpv)
            ("\\.m4v$" . einar-browse-url-mpv)
            ("\\.mkv$" . einar-browse-url-mpv)
            ("\\.pdf$" . einar-browse-url-pdf)
            ("." . eww-browse-url))))
-1:-- Speed improvement hack for dired with EWW (Post Einar Mostad)--L0--C0--2026-05-10T14:47:00.000Z

Case Duckworth: May I recommend declaring bankruptcy from time to time

Configuration bankruptcy is someting of a meme in the Emacs community, to the point where there is a dedicated wiki page describing the phenomenon. As a fully-programmable text editor, Emacs configuration tends toward spaghetti over time, at least for many users (including myself). And for many of us, the only remedy for an unintelligible, slow, and tangled Emacs configuration is wiping the whole file and starting again.

I admit that I can be a perfectionist in some things. I also, for some reason, enjoy configuring Emacs, so I tend to tinker with it in my spare time. As a result, I’ve declared .emacs bankruptcy somewhat more than the average bear: when I finally stopped counting, I’d made it up to 12 or 13.

A few years ago—either because I got busier with work, got less interested in perfecting my setup, had a child, or whatever—my Emacs configuration more-or-less calcified. I had a custom macro for installing packages and grouping their configuration; I had plenty of custom functions and macros to mold Emacs perfectly to my needs; I had a system whereby I didn’t overwhelm my configuration with too many packages du jour.

As of April 2026, I have declared .emacs bankruptcy yet again.

The Michael Scott 'I declare bankruptcy! meme with the GNU logo superimposed on his face.

As is usual with my bankruptcy declarations, the reasons are many, unfocused, and inchoate, but basically boil down to “I was bored.” Not that I have any reason to be bored: I have a toddler and a one-month-old at home, and I’m feverishly looking for work in one of the worst economies in generations. So maybe bored isn’t the right word.

My ~/.emacs (it’s actually in ~/.config/emacs, but who’s counting) was, despite my best efforts, getting brittle again. I found myself, once again, with the itch to explore and install new packages. I kept having to look up the source of functions I’d written years ago to remember how they worked. So I made a ~/emacs2 directory and ran emacs --init-dir=~/emacs2 in my shell, and was off to the races.

I’m really not changing all that much, though. The main theme of this go-round is that I’m not afraid of using external packages if that means I can have the functionality I want without having to think about it too hard. Thus:

  • I’m using use-package to declare packages.
  • I’m using super-save-mode to save buffers without having to think about it.
  • I’m using snap-indent instead of a complicated auto-indentation/whitespace-cleanup thing (though I might change it back; I think it might be causing a subtle bug in my workflow).

In addition, I’ve refrained from copying and pasting all my old options, which I do every bankruptcy. It’s a good chance to reëvaluate the features I really need while pruning those I don’t (or that I’ve been working around without realizing it for a while). Plus—and maybe I’m just strange for this one—it’s fun!

The theme for this month’s Emacs Carnival is May I recommend…, and my recommendation is tearing out your configuration from time to time and starting over. You’ll never really know who you’ve become until you do.

-1:-- May I recommend declaring bankruptcy from time to time (Post Case Duckworth)--L0--C0--2026-05-10T00:05:00.000Z

Marcin Borkowski: describe-personal-keybindings

Some time ago one Emacs user made themselves a local web app showing various Emacs keybindings – basically, a web-based Emacs cheatsheet. It’s definitely a nice project even if not for me – if I were to create something like that, it would run in Emacs and not in the browser, it would definitely mention transpose-.* commands, and it would never be dark-mode-only;-). But it’s a really cool and nice project nevertheless! That’s not the topic of this post, however. In a Reddit discussion about this tool someone mentioned a command that blew me away: describe-personal-bindings.
-1:-- describe-personal-keybindings (Post Marcin Borkowski)--L0--C0--2026-05-09T03:53:14.000Z

Corwin Brust: last-rev.pl

last-rev.pl

As returning readers will know, I produce (or try to produce) regular builds of Emacs for Windows. When things work, these produce pre-compiled binaries as an installer and unpack-and-run zip files. You can find links to the latest set for each branch in the box at the top-left each page on the site.

Today's post is about one program out from the middle of the bucket-brigade of data I have created, generally in an effort to avoid unneeded queries of the upstream (Savannah or Savannah mirrors hosted) repositories.

-1:-- last-rev.pl (Post Corwin Brust)--L0--C0--2026-05-08T18:59:59.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!