Irreal: Sdcv-quick Update

Years ago, when I learned from mbork how to get my own copy of Webster’s 1923 dictionary my dictionary use was vastly improved. If you don’t know why having Webster’s 1923 is a big thing, here’s my original post on it from 2015.

For Emacs users, the package you need is quick-sdcv.el, an update of the original sdcv package. Actually, quick-sdcv useful for a lot more than just Webster. You can even use it to access the Oxford English Dictionary from within Emacs. Obviously, there’s a lot to like.

The point of this post is to pass on the announcement that sdcv-quick has been updated. If you do any writing at all you need sdcv and Webster’s 1923. Having the OED is a bonus. Happily, it’s easy to have it all in Emacs with sdcv.

-1:-- Sdcv-quick Update (Post Irreal)--L0--C0--2026-06-02T14:13:44.000Z

Raymond Zeitler: Change Emacs Cursor to Indicate Overwrite Mode

The text editor I'd used for 20 years on an MS-DOS platform would change the shape of the cursor to distinguish between insert mode and overwrite mode. A filled rectangle (or box, in Emacs terms) indicated overwrite mode; an underscore (hbar), insert mode. It's a nice way to make overwrite mode obvious.

The video starts out with Emacs in Insert Mode. Then Overwrite Mode is activated, which changes cursor-type from hbar to box. The word "Overwrite" replaces "Insert" to demonstrate the effect.

Incidentally, you might enjoy listening to some sound while playing back the video. One of my favorites is "Forest Voice" from https://mynoise.net, by Dr. Stéphane Pigeon.

Anyway, here's a function to implement that behavior in Emacs:

(defun zeit-change-cursor-shape ()
  "Set cursor shape depending on overwrite mode.
When overwrite-mode is nil (off), set cursor-type to hbar.
Otherwise, set it to box."
  (interactive)
  (if (not overwrite-mode)
      (setq cursor-type 'hbar)
    (setq cursor-type 'box)))
-1:-- Change Emacs Cursor to Indicate Overwrite Mode (Post Raymond Zeitler)--L0--C0--2026-06-02T14:13:04.078Z

Charles Choi: Opening macOS Finder Folders in Emacs with Scrim

img

TL;DR

If you use both Scrim and Emacs on macOS, you can “Open in Emacs” a file or directory from Finder via the “Quick Actions” context menu. This is implemented as a macOS Shortcut, shared as an iCloud link:

“Open in Emacs” Shortcut iCloud Link

Motivation

I find macOS drag-and-drop operations from Finder to Emacs (in particular, the NS variant) to be frustratingly inconsistent.

  • Dragging a file or folder from Finder to a non-Dired buffer will visit it.
    • Not always! This behavior can be mode-specific.
  • Dragging a file or folder from Finder to a Dired buffer will copy it.
  • Dragging a file or folder from Finder to the Emacs icon in the Dock will visit it in a new frame.

Add to that, drag-and-drop isn’t graceful with a long traversal path on a large screen.

Ultimately, what I want is a single consistent action to “Open in Emacs” a file or directory from Finder. This post describes a solution for achieving this using the Scrim and macOS Shortcuts apps.

Background

Scrim

Scrim is an Org protocol proxy app that I had published on the App Store last year. Implementing Scrim was largely an exercise in reverse-engineering emacsclient to be a macOS app. This is because macOS apps these days (macOS 10.14+) are packaged to execute as a hardened runtime (aka “sandboxed”). Among the many things a hardened runtime restricts is the ability for an app to exec another program outside of its sandbox (like emacsclient).

In lieu of that restriction, macOS provides different APIs to let apps work with other apps, among them Services (more below), Intents (a whole different topic worthy of another post), and custom URL schemes.

A custom URL scheme is what Scrim provides to allow other apps to do emacsclient-like things like opening a file. By design, Scrim does not surface all the capabilities of emacsclient such as arbitrary Elisp execution. The custom URL scheme itself is scrim://.

Currently the scrim:// URL scheme supports the following two actions:

  1. Visit a file or directory (e.g. scrim://open?file=~/.profile)
  2. Open an Info node (e.g. scrim://info?node=(eshell) Top)

For this post, we will concern ourselves with (1) visiting (opening) a file or directory.

Note that on a system where a custom URL scheme is installed, any app on that system can open said custom URL scheme.

Services

The macOS Services API allows an application to access the functionality of another.

Apple uses this API to provide tools to help orchestrate workflows between different applications, namely AppleScript, Automator, and Shortcuts. Note that as of this writing, AppleScript and Automator are in maintenance mode, and Shortcuts is intended to supersede Automator. Once a workflow is defined, it is usually accessed via a context menu sub-menu labeled “Quick Actions” or “Services”.

“Open in Emacs” Shortcut

With the above background out of the way, let's turn our attention to the Shortcut itself.

img

The shortcut invokes a Python script which forms the scrim://open?file custom URL and then opens it with the open command line utility.

1
2
3
4
5
6
7
import sys
from subprocess import call
from urllib.parse import quote

buf = "scrim://open?file={0}".format(quote(sys.argv[1]))
cmdList = ['open', buf]
call(cmdList)

This shortcut can be installed via iCloud link: “Open in Emacs” Shortcut iCloud Link.

When installed, the menu item "Open in Emacs" will appear in the "Quick Actions" sub-menu when the context menu is raised on an Finder item.

“scrim link” Shortcut

img

What if you want just the Scrim URL to open a file or directory instead? The shortcut "scrim link" shown above provides that, putting the URL into the system clipboard to paste into another native macOS app like Notes or TextEdit. Such apps that recognize custom URL schemes will treat the URL as a “live” link.

img

This shortcut is available at “scrim link” Shortcut iCloud Link.

Closing Thoughts

While the behavior of "Open in Emacs" seems modest, a lot of things need to happen under the hood to orchestrate the different apps required to make it happen on macOS. But taking a step back, I'd observe that this is not unique to just macOS alone. Other contemporary operating systems are following suit as seen with Snap (Ubuntu) and Flatpak for Linux, and UWP for Windows. Such isolating practices by OS vendors are not going away.

Running counter to this is the spate of interest in orchestrating apps and/or services together using AI tools, whose approach so far is to bypass all hardened runtime boundaries.

Then there is comparison to the Emacs ecosystem, where orchestration of apps (or rather modes) is routinely done via Elisp. By implementation circumstance there are effectively no concerns for security boundaries within the internals of Emacs.

There's a lot of ground to ruminate on, in particular software malleability and orchestration, which I intend to do with future posts on this blog.

-1:-- Opening macOS Finder Folders in Emacs with Scrim (Post Charles Choi)--L0--C0--2026-06-02T02:00:00.000Z

Jakub Nowak: Radical Builtins

This is my entry for the June 2026 Emacs Carnival Underappreciated Emacs Builtins. There is a lot of functionality in default vanilla Emacs that is certainly less talked about. I'm going to constrain myself to talking about specific functions that exist, instead of overarching themes like portability.

Regional Commands

Some commands in Emacs work in the current region/selection. This is useful with undo in particular, because you can undo a change that happened in a specific area instead of having to go back through the whole undo history (or using a package like vundo).

Buffer Narrowing

Focusing a single buffer down to just the contents you want to look at makes parsing large code files so much easier. It seems like a basic thing but it helps me out more often than one would think, even when writing to focus on a specific paragraph or sentence to edit in isolation.

Indirect Buffers

Being able to "clone" a buffer also seems like such a trivial functionality, but it has so many uses. I particularly like this for editing large pieces of inline C code in Chicken. First M-x clone-indirect-buffer, then narrow to the C code string, then change to C mode. The narrow-indirect package speeds up this process a bit, but all of this functionality is built in by default.

Register

These might not seem too distinct from bookmarks, which everyone and their grandmother knows about, but I don't see people talking about registers enough. I work with big repos, monorepos that usually contain code for all the internal packages, and multiple apps. Being able to quickly say "I wanna jump back here" is unbelievably valuable, especially in combination with jumping to definitions and the like.

Directory Local Variables

Directory local variables are a silent workhorse for me, and don't get enough love. Knowing that these exist will save you endless config time when working across projects with different standards. Or, in the case of working with Scheme, different Scheme interpreters in Geiser. I like working with both Chicken and Gambit, and being able to set the default in a project easily is so helpful, even though it is ultimately trivial.

This goes beyond basic variable customisation too, you get a whole eval hook to play with. Some example uses of this are to automatically log in to AWS when the project is opened, or automatically starting the project for debugging, etc.

Tramp

As I write this there haven't been many submissions for this carnival, but I feel like Eshell and Tramp will get a lot of mentions. While obviously I do use Tramp for accessing my other machines, something that I hear about less often is that Tramp can read and write into more places than just another remote machine via SSH. There's obviously using it for sudo, but it works great for accessing files inside of Docker containers too (useful when working with devcontainers), and that functionality extends to:

  • Podman.
  • Kubernetes.
  • Distrobox.
  • Even flatpak sandboxes.

Macros

Probably should go without saying that macros are a very useful part of Editor Macros, but I feel that the standard macro functions get overshadowed in discussions, usually by proper Lisp scripting.

Repetitive, one-off tasks are everywhere. Personally, one of the first few keybinds I memorised in Emacs (even before navigation) was F3, F4, and C-x e to record, stop recording, and execute a macro. This single feature has saved me countless hours in doing menial crap such as:

  • Inverting cond statements in Scheme.
  • Stripping whitespace, quotation marks.
  • Editing CSV columns.

And the list goes on. There's so many times that I have run into a task that is repetitive but automatable, but not likely to come up again so not worth scripting. Being able to go "well okay, let me just press F3 and do it once, then just C-x e until I'm done" has saved so much pain.

Scripting Things

This final section I want to dedicate to the variously useful elements of Emacs Lisp.

Timers

Automatically running shell commands or other things at a given time is great, and these are also easy to manage with M-x list-timers. Who needs cron jobs?

Advise

I see advise generally frowned upon on in scripting discussion (for good reason, it can make code messy), but knowing the feature exists is occasionally really helpful.

Take neotree, for example. I want the directory of neotree to be tab-local, so that I can switch between tabs and have it persist. Emacs' tab bar mode doesn't have any hooks for tab selection, but that doesn't matter, because we can make our own.

(defvar tab-bar-select-tab-hook nil "Hook for `tab-bar-select-tab'")
(advice-add 'tab-bar-select-tab :after (lambda (x) (run-hooks 'tab-bar-select-tab-hook)))

Likewise, neotree doesn't have any hooks for when the root changes, which I want to keep track of to automatically update the tab directory. Again, that won't stop me.

(advice-add 'neotree-change-root :after #'theurgy-change-tab-dir)

Advise is one-of-a-kind, and while you definitely don't want to rely on it, sometimes there would be no other option and this system deserve praise for thinking about those cases.

Processes and Filters

For the last point here, I want to show off something that I've automated recently: AWS sign in. You can find the whole source code in my config here, but the relevant function is below.

(defun aws--login (role)
  "Internal login function --- handles the command as a process, and prompts for MFA."
  (let* ((process-name (format "%s-%s" aws-cli-auth-provider (replace-regexp-in-string "[/:]" "-" role)))
       (buffer (get-buffer-create (format "*%s*" process-name)))
       (prompt-regexp (rx (or "Enter verification code")))
       (prompt-sent nil))
    (with-current-buffer buffer
      (erase-buffer))

    (make-process
     :name process-name
     :buffer buffer
     :command (list aws-cli-auth-provider "login" "--force" "--skip-prompt" "--role" role)
     :filter
     (lambda (proc output)
       (with-current-buffer (process-buffer proc)
       (goto-char (point-max))
       (insert output)

       (unless prompt-sent
         (let ((buffer-contents (buffer-string)))
           (when (string-match-p prompt-regexp buffer-contents)
             (setq prompt-sent t)
             (let ((token (read-passwd "MFA token: ")))
               (process-send-string proc (concat token "\n"))))))))
     :sentinel
     (lambda (proc event)
       (when (string= "finished\n" event)
       (run-hooks 'aws-post-signin-hook))))))

Basically, I want to sign in to the AWS CLI for a specific role. This usually works great, however sometimes it might as for an MFA token, so if I run the login command with just shell-command it won't do anything if it hits that snag.

However, if I run the command as a process, well, you can easily wrap that prompt and have Emacs ask for the input in the minibuffer. That's what the filter is doing, it just checks if the process has sent text asking for a prompt and if it has, read that with read-passwd and send it to the process. When I was first thinking how to write this, I expected it to be much more annoying. But this is actually stupidly simple.

-1:-- Radical Builtins (Post Jakub Nowak)--L0--C0--2026-06-02T00:00:00.000Z

Sacha Chua: Transcript of chat with Matei Candea about Emacs and AI

This is an edited transcript of my chat with Matei Candea, an anthropologist who is curious about the Emacs community and AI. Sharing it here with permission so that it becomes a thing I can refer to and in case it sparks further conversations. AI is a bit of a contentious topic, so I hope people will be patient and kind as we figure things out!

Related links:

Expand for the transcript

Matei is an anthropologist; ethnographic research

Matei: I'm an anthropologist. What I actually do for work is to do ethnographic research, to interview people. I've written a lot about scientific communities. For instance, I've written articles on behavioral scientists who work with animals and how they think about knowledge and technology and stuff. Completely independently of that, I kind of got into Emacs and got really excited. About four years later, I was, like, wait a minute, why don't I do an ethnography of Emacs as a community?

Sacha: Really cool people.

Matei: Right? Really cool people.

Curious about Emacs as a community in the time of AI

Matei: I think what I'm really saying is Emacs as a community in the time of AI and how that's shifting or not shifting how people are using it, and what it does. I've spoken to Prot on Monday. That was the first interview I did, and we had a great chat. I basically asked him how he got into Emacs and what it meant to him and what his relationship is to the community and stuff, and then a bit about AI and then a bit about what he feels are the interactions between the two. That's broadly speaking what I would be interested in doing with you. If you think there's a broader conversation, we could live stream and have an actual chat about how people use Emacs. By the way, I'm very happy also to tell you where my own trajectory was that I got into Emacs weirdly and randomly about a year before ChatGPT really hit the mainstream. The thing that you read by me was written because me and Ella together were trying to figure out Cambridge's response to AI as a university. Like, what are we going to do about it? If I'm going to be talking about that, I need to know how it works. But I don't want to use AI in my own actual work or in my teaching, because I think it's a bit dodgy. I don't really like it. Why don't I just do it with this kind of side project I've got, which is learning Emacs, right? And the weird paradoxical thing was that I now basically kind of live in Emacs. My email is mu4e. If you saw my screen now, the notes are basically a narrowed Org buffer with questions. Everything's email. But I don't think I could have got there that fast if it hadn't been for the fact that I started asking ChatGPT, like, "Oh, this isn't working. Can you just write me a defun that does this?" I'm not completely vibe coding. I'm trying to learn Elisp at the same time, but I'm in this weird position where... Anyway, this is why for me it raised these questions of: what does learning Emacs in the time of AI mean? As you can probably gather from the manifesto, I'm not pushing it at all. I'm really ambivalent about the use of AI. Anyway, would you be happy to do an interview like I did with Prot?

Sacha: Yeah, we can certainly do that. In addition to whatever I can share from my personal experiences, I think your interest in understanding and describing the community and the culture and how it's interacting with this AI thing, I think it'll offer a perspective that is different from what you usually see, because Emacs users have had this long tradition of fiddling with things and making it really malleable and fitting it to them and figuring this out in dialogue. It's figuring out in dialogue with themselves as they figure out their workflows, with the software as they learn from the code, with other people, with resources on the internet not necessarily attached to specific people. That's got a really long history. It's really interesting to see how AI both has plus sides and minus sides in this whole mix. It definitely, I think, will offer some insight that you won't hear with the frothy AI hype that other communities have. It's all very interesting.

Matei: Amazing. Let's start with a general kind of interview thing.

How did I first get into Emacs

Matei: How did you first get into Emacs?

Sacha: I was going through all the books in my university library about computer science. One of them was Unix Power Tools. I was like, there's this chapter on Emacs, and it mentions Tetris and other things. What is going on here? I tried it. It was great. I liked it. Then in fourth year or so, my screen stopped working. I didn't want to replace it. But there was Emacspeak. I was amazed. Lots of people had put together Emacs so I could use the computer with a broken screen. I could still read it periodically, if I tilted it and kind of looked at the low contrast thing
 The speech synthesis worked just fine. I'm going to program this way. I'll plug into a monitor when I'm back in my room. But if I'm out and about, I have this other way to do it. Something that maybe most programs would not have anticipated, but because somebody had built it for themselves, it was something I could use. Beffore I got into Emacsspeak, I got into Planner Mode because I was a university student and I was taking notes. Planner Mode was an easy way for me to keep track of tasks. It was more flexible than other to-do managers. It's one of the packages that was popular before Org Mode.

Matei: Right, right.

Sacha: I started using that to write my blog. Blogs had just been invented around then. I was figuring out, how do I export RSS out of this? I was able to customize it to do that. I liked it so much I emailed John Wiegley, who had created Planner Mode. I said, hey, I can help you fix bugs. He said, great, you're the new maintainer now. Which was actually very good for me because I was a university student in the Philippines, and Philippines, and normally we don't get to work on anything really cool. Suddenly I was in this global community of people. There was a mailing list. People would send in questions or feature requests. I would share the things that I was working on. They were very, very patient with me. Like that one time, one of my changes accidentally deleted somebody's notes and they were still nice to me afterwards. The community has always been part of how I experience Emacs. Learning in public has also always been part of how I've been figuring out what I can do with it and changing it to fit my needs. It's very idiosyncratic as they are sometimes, has also always been part of my experience of Emacs.

Matei: When did this start?

Sacha: Very shortly after I started Emacs, I started blogging with it. My first blog post from that is 2001.

Matei: Right. You were studying computer science?

Sacha: I was studying computer science, yes.

Matei: Are you a computer scientist now? What do you do when you're not doing Emacs?

Sacha: Most of the time, I'm still focused on full-time parenting, which is why I'm going over to the freezer now to remember to put yogurt in the freezer. I do a tiny, tiny, tiny bit of consulting, but consulting, but for the last 10 years or so, I've just been focused on parenting. Playing with Emacs and being in touch with the Emacs community has been one of the ways that I've kind of kept sane. I've enjoyed the intellectual puzzles of: I have this thing that I want to do, how do I do it with code in ways that I can fit into five minutes here, ten minutes there of my life.

Matei: Do you do any other coding or just Elisp?

Sacha: JavaScript, Python on occasion. Some of my consulting involves making little JavaScript prototypes for ideas that my client has, but it's really just an hour a week, maybe less. But for fun, I still write a bit of JavaScript and Python. Emacs Lisp, however, is what I usually write because it's so much easier to do things when you've got the full editor with you.

Matei: Yes, that makes sense. I've got a million questions, but I'm going to try and do them in order. You've said a little bit about this already, but

What do you love about Emacs?

Matei: what do you love about Emacs?

Sacha: You can come up with a crazy idea and you can actually make it happen. So, for example, I've been doing a lot of conversations, interviewing people or working with my sister's interviews. I always like turning these into text because text is a lot more searchable. Chapters and things like that too, right, so that people can jump to just the part they're interested in. I don't know how other tools do it, but I love the fact that I can modify Org Mode so that I can capture timestamps. Wall-clock time is easier for me to work with. I can say, okay, while I'm typing, I just use an abbreviation to put in the timestamp that's the current time and my rough notes. I have another piece of code that translates that into offsets from the start of the video based on YouTube's live stream or the file name of the video. Then I can paste that into the subtitle file so that it automatically puts the chapters in roughly the right places. As I come up with little workflow ideas, I can actually implement them.

Community

Sacha: I also love the community of it. Looking through the blog posts or as I put together Emacs News every week, there's always all these interesting examples from people who are asking the same questions about about "What is it I want to do?" and "How can I do it 0.5% better?" They write these little functions. I'm like, oh, that is a fantastic idea. I get to absorb that into my life. Because I'm seeing it in the context of their blog post or their video, you get a glimpse of other people's lives as expressed through code, because all of the code is very personal. That is one of the things that is good about the fact that people are using AI sometimes to generate this code. They can make things that things that punch above their weight. A newcomer to Emacs can have customized functions that let you fully appreciate its power. But on the other hand, if the AI is just generating this code, you don't get a sense of like, where's the blog post this is coming from? Or who would I talk to to keep up with other crazy ideas they come up with? You're limited to just your ideas. Then there's the whole thing about license-washing. Most of the people release their code under GPL because it's Emacs, but the large language models never mention that. They never say, you also have the right to go and share this and modify this and build on top of it and contribute back to the community. Sometimes it doesn't feel right, the code. It doesn't quite get the conventions and the idioms yet. So the things that I love about Emacs are generally the fact that it can fit me like a glove and it's got this community of people who are also exploring what is possible as crazy as ideas sometimes get. There's always some way to hack it in.

Do you know how big the community is?

Matei:

Do you know how big the community is?

Sacha: I have no idea. We generally feel like it's a lot smaller than VS Code and probably a lot smaller than Vim. It depends, of course, on if you're talking about percentage, it depends also on... There's a lot of Clojure developers using it, because it's the standard Clojure way of doing things, but there are probably a lot fewer Java or JavaScript people using it because a lot of people are in VS Code instead. I used to do Google Analytics tracking on my website, but I stripped all of that out because cookies and tracking and all of that. When people ask me how many people read this stuff, I have no idea, but I do know that every time I look for Emacs News, I'm delighted by the breadth that I come across. To me, it feels like there's a thriving community that's large enough for my interests.

Matei: Cool. You're the second person I've actually spoken to. The first person was Protesilaos. I'm struck by the fact that from a sample of two, I've got two people who are not based in the US, who are super international, and also who are not developers.

Sacha: That is a fantastic thing about it. I love that we have researchers and sourdough bakers and knitters. Of course, the programming part is still there, but a lot of people end up getting into some kind of programming because of Emacs. Emacs is the only thing they ever code, and they don't even think of it as coding. It's just like, I do this, but I wanted to be able to do this, so I learned how to do Org Mode and source blocks, and that's all I can do, but it's great. I think that's really interesting because when you talk to people about their origin stories with Emacs
 Sure, of course, you have the pockets of people who are like, I'm a computer science student and my professor said use this, so I'm using this, and so forth. But then you get these random high school music students who are like, oh, yeah, I just saw this video and I thought it looked really cool, so I taught myself how to do that. I don't know anybody else who uses it in real life, but I like it. Musicians using it live to do performance... Where are these people coming from? But they come across it, and it just strikes a chord with them, deep in their souls. It appeals to a certain tinkerer type, I guess. They just continue with it. They get stuck. Sometimes they leave and they come back, and all that stuff
 But the breadth is one of my favorite things about Emacs.

Matei: Do you think that most of the people in the community are probably developers? Because when you were saying the community, you compared it to Vim and VS Code, which is to think of it really as an IDE kind of thing.

Sacha: That's usually what people talk about, right? Because usually when people are thinking, how popular is this, they're stacking it up against developer tools because those are the surveys that the development websites do. Stack Overflow or State of Clojure or whatever. They'll ask people, “What editor do you use?” But given Emacs' surprising popularity among people who are, for example, diagnosed with ADHD and find that Org Mode is the only way they can manage their brains


Matei: Is that a thing? That's really interesting.

Sacha: In a number of Reddit threads that I've seen, people are like, yeah, I'm not a programmer, but Org Mode is the only way that I've figured out how to manage my brain. Or people will come to Emacs from something else specifically for Org Mode because of the way that it can help them manage their tasks or agenda, because they can sculpt it to fit what their specific workflow could be. It's amazing. Of course, we've got the writers and the researchers who are like, "I love publishing beautifully typeset things, but I don't like working with LaTeX all that much, so let me just figure out the template once."

Matei: Yeah, totally. I really came to Emacs because I was looking for an outliner. I'd been writing in Markdown for a while. I was really getting sick of the heavy Word stuff. And I was, like, Org Mode, omg, it's amazing! Then from there, I was bitten.

Do you have any frustrations with Emacs?

Matei:

Do you have any frustrations with Emacs?

Sacha: I would like to have more time in the day to fiddle with things. In terms of the balance between fiddling with my config and doing the thing that I want to do, if I sandwich it so that I do my 5 to 15 minutes of Emacs fiddling at the start, then I'm motivated to go through the task because I want to test that my improvement works. Then it becomes a good balance for me. I don't spend all the time feeling like I'm yak shaving, and I don't spend the time struggling with workflow because I didn't take the time to automate it. I would like to have more time, because I always come up with more ideas in the middle of something. I know this is possible. I just have to sit down and do it, and it'll be great. But okay, I have to wait till my next 5 to 15 minute window where I can fiddle with it again. The other thing that I've been trying to figure out is: how do you help people develop that intuition for how to do things, how to make Emacs do things? We see a lot of people come into the community. They might get stuck on some things. The tutorial is very useful, but it can be overwhelming. The whole Emacs thing can be very overwhelming for people. How you help people get through that part is something that's of great interest to me. Bringing it back to AI and large language models, the fact that people can sometimes have a conversation with this endlessly patient tutor where they might be too embarrassed to ask their questions on a mailing list or a forum, I think that's fantastic. But also, going to your manifesto's points about learning by doing and education and the eureka moment, we also don't want this quick and easy help to rob people of the understanding that they get from looking at it and tweaking the code or learning how to read through the source code themselves. There's just so much there that I would hate for people to just get stuck in the “please generate this code for me" level rather than be able to learn this is how I start learning from other people's source code so that I can come up with more ideas.

Matei: That's right. That's also what I think basically. Here's an interesting question.

Would you ever leave Emacs?

Matei:

Would you ever leave Emacs?

Sacha: I cannot imagine an editor at the moment that would let me get away with nearly half of the things that I do, but maybe even less. Right now, I've got so many odd little customizations for it. For example, on my phone, I'll use Orgzly Revived to capture a quick note so that I can go back into Emacs later and do it. But even though I'm comfortable programming in JavaScript and Python, and there are lots of tools available there, the interactive interface part of things is something that I don't see any other program give me the same kind of platform of support or building blocks to play with. Who knows? If some day, this thing manages to support all of my hacks built on hacks and gives me that same kind of feedback loop, but it's also multithreaded and graphical and whatever, I might give it a try. But at the moment since I can get away with so much in Emacs and I know that people behind the scenes are working on adding even more to it, it's okay, long term. It's been around for 40 years. It'll be around for... Probably it'll outlive me. I don't have to worry too much about giving up on it.

How important for you is the free software bit of Emacs?

Matei:

How important for you is the free software bit of Emacs?

I was on Mac when I got into Emacs. I went to GNU Emacs to download it and it said, we made this available to people on proprietary systems in order to teach you to free yourself. I was like, huh? I downloaded it and I'm now running Arch Linux. It definitely worked. Richard Stallman has downloaded himself into my brain. How much is the free software bit of it important to you in using Emacs?

Sacha: I'm not a purist. I will happily be the interface using the non-free things. For example, when we were doing EmacsConf, the first few years before Whisper was around, I was the one doing like, okay, fine, YouTube has this subtitling thing that we can grab the stuff from. Yeah, it's a non-free service, but I will happily take advantage of it in order to make the information more free, and things like that. I use both free and non-free things, but I love the single-minded focus that a lot of people have on freedom and making sure that other people enjoy these rights. For example, in the Emacs community, a surprising number refuse to use JavaScript because a lot of JavaScript is non-free software. I want to make sure that my website still makes sense without JavaScript. EmacsConf, there are ways to participate even participate even without JavaScript. You can use MPV to watch the stream. It's all free software. You can use IRC to chat. All that stuff is very important to people, and that's great. I love the fact that for a lot of people, they really care about making sure other people can continue to enjoy these freedoms to modify things and to build on it. Every so often someone comes into the Emacs community and they're like, oh yeah, I want to make money making packages here. I'm going to put my package behind a paywall. You've got to send me a donation in order to use it. Then they get smacked down so hard. Usually the way it works is someone will then, you know, take a look at their README and say, okay, that looks vibe-coded. I can do it faster and I'll do it for free. That's the usual response to this stuff. Yeah, here's the thing that you're trying to sell, but it's free.

Matei: So that never works. I was struck by this. It seems to be so absolutely immune to takeover by proprietary stuff.

Sacha: I mean, it's a startup hustle mentality in other communities, but in Emacs, it does not fly. Mostly because people are, like, are, like, I know the tools you're using, I can do that better myself. There are people who do get sustained by donations from Emacs community members, but it generally is more of a "I appreciate your work and I will send you this voluntary donation" instead of your paywalling your stuff behind this thing, which feels very much against the ethos of the Emacs community. It's been interesting to see the AI hustle "software as a service or product type" thing try to infiltrate the Emacs community, and they are having none of it.

Matei: Interesting. Why do you think it's so resilient to that?

Sacha: Because we've had such a long tradition of sharing things for free, building on top of things that people have freely shared: not just like free as in beer, but free as in you've got the source code, you've got all the rights to do whatever you want with it, including for free. That's baked into the community. Any time someone comes in and tries to say, oh yeah, I've got this commercial packaging of Emacs, it's all rights reserved, people are like, yeah, there's probably a GPL violation right there, so let's go.

Matei: Cool.

How do you explain your passion for Emacs to non-Emacs users?

Matei: How do you explain your passion for Emacs to non-Emacs users?

Sacha: I don't usually. I love the fact that I can tinker with it, right? If it clicks for people, it clicks. But if it doesn't click for people and they don't necessarily want or need that, then it's okay for them to use something else. I love the fact that people are using or even shifting to other editors. For example, we've had a couple of people announce that they're leaving Emacs recently because vibe coding has made it possible for them to build native applications and they don't have to build it on top of Emacs anymore. They can finally get their Vim config set up the way that they wanted to because the LLM can generate that stuff for them. Whereas in Emacs, it would have been a lot easier to write it themselves, but now they can do it with VS Code or whatever. It's great because the more people are experimenting with interesting ideas, even outside Emacs, the more we get to steal those ideas and then bring them back. You see a lot of this sometimes. You see people re-implementing cool ideas from other editors or other tools. To me, it's totally okay if other people use something else, especially if they tell me the cool stuff that they think only that editor can do. Because I'm like, that sounds like an interesting feature. Do tell me more. There was an interesting talk by Jeremy Friesen in either last EmacsConf or the one before that, about mentoring and how he's no longer trying to push people to use Emacs. He wants to share the general workflow practices he's using. If he's pair programming with someone, he might say, how do you jump to a specific function definition? They might show him something, or they might realize that's a thing. I can go look in my editor how to do that. He might show, this is how I do it. That's the general idea. Sometimes when people start talking workflow, then talking workflow, then talking workflow, then people who are not using Emacs will go, "That looks really cool. How do I do that?" Then that?" Then you send them down the path of: get it installed, go through the tutorial, that sort of stuff. But it always helps to have that specific reason, the thing that they want to be able to do. For me, for example, I love the way that Org Mode lets me have my notes and the code and the links. It's all one big thing. I don't have to think about, oh, okay, I have to do everything in Python because that's what Jupyter does. I can do some of it in Emacs Lisp, and I can do some of it in shell scripts, and I can do some of it in JavaScript or Python. It's like all this big mess Org Babel kind of thing. Yeah, because your brain might not be in tune with all those different languages, but it works for me. If other people see that and they say, I want to do that too, then that's when you help them get into Emacs. But aside from that, I don't talk to people in elevators and say, have you heard the good news?

Matei: I was wondering even more broadly than kind of people who are already coding with a different editor. To tell you a story... My cousin is also an anthropologist. He's an anthropologist in France. I've known for years that he was into Linux and free software and stuff. When I got into Emacs, he said, you know I've been doing Emacs for 10 years. I was like, what? How? What? And he'd never told me. I realize now, having been doing Emacs for four years, I can't talk to my colleagues and friends about it because they look over my shoulder and it's like, what are you doing? This looks like it's from the 1980s. Even trying to explain to people what Emacs is... I don't mean coders, I just mean people. My cousin said, yeah, I talk to people about free software all the time. I've never talked to anyone about Emacs. It's just so weird.

Sacha: I think that's why the community is so important, right? I aggregate a lot of blogs on Planet Emacslife on Planet Emacslife so people can bump into each other. There are a lot of meetups, some of which we host on BigBlueButton... There are meetups, by the way. If you check under Emacs News, there's actually a very active London meetup.

Matei: I haven't yet.

To what extent do people meet in person with Emacs?

Matei: To what extent do people meet in person with Emacs?

Sacha: Apparently, a lot of people meet in person whenever they're lucky enough to get a sense that there are actually other people in their general geographic location who are interested in this. But there are also a lot of people who meet online. Org Meetup has a meetup every month that has about 20 people in it. Emacs Berlin has a meetup that's hybrid, and so it's both in person and online. There's Emacs Asia Pacific. There's a whole list of meetups in Emacs News, which is that newsletter that I do every week. I list upcoming events, and there's also a link there to the calendar as well as to the user groups page which lists by region. There are a lot of people getting together about Emacs because a lot of times, you learn about Emacs by looking over someone's shoulder, physical or virtual, right? This is how you learn about things that you would not have even thought of asking an AI about. They're doing a demonstration or they're doing a video, and you're like, what is that thing that you just did? They had no plans to talk about it because it's just something they take for granted. It's a keyword shortcut or a command. It's just part of the workflow. They don't think about it anymore. Or it's even as simple as "What's that theme? What's that font?" Because people can see it, can see somebody doing stuff with Emacs, they get inspired to learn more and to adopt that into their workflow. That is one of the things that I love about how people learn Emacs. It's very convivial, right?

Matei: Yeah.

Learning in public

Matei: You said the phrase earlier: learning in public. In one sense, that sounds scary. Learning in public, making mistakes in public and stuff. You said it as a really good thing. Tell me more about learning in public.

Sacha: My favorite kinds of blog posts is when I'm proud of myself for figuring out something clever. Like, okay, here's this function function to do this thing. I had to figure it out. It was hard. It took like a day or two to do it. Then someone comes by in the comments and says, oh yeah, that's built in.

Matei: Yeah, I've been there.

Sacha: "You just change this variable." It happens so often. The reason is because Emacs is so big, right? There are variables and functions that I would not think of coming across. Maybe I'm not using the right words to search for them, or whatever. If you add to that the entire package ecosystem and as well as the things that are not people's packaged code, snippets in people's config and whatnot... Chances are someone has come across the same problem that I'm thinking about and has come up with a more elegant solution for it. If I'm not using the same words, I might not find it. One of the things that I like about large language models is that even if I use my words, sometimes it will suggest something that does that translation, right? It's an approximate search. But even if I don't have that, if I'm writing about something, then I have that opportunity for somebody to say, oh yeah, you should check this out. Or several years later, someone might also say, that is exactly what I was trying to do. I'm taking your code. I've built something on top of it to make it even better. For me, writing about what I'm learning with Emacs is a great way to learn even more from the community. I keep trying to convince people, yes, please, even if you're a beginner, write about what you're learning, because it's a great way to crystallize that knowledge for yourself, become part of the community and part of the conversations, and learn about things that you would not have thought of asking about.

Matei: Well, I'm following your example. I'm trying to write my config in Org Babel at the moment, partly as a way to say, wait a minute, what is this thing? How does it work? It's so useful. But one thing I was wondering, and it's partly also just a practical question,

Disclaimers

Matei: I've never tried to contribute or to post anything on anything, partly because I worry that my stuff is crap.

Sacha: If you put a disclaimer, that way they know they're reading it for the idea, but not necessarily the Emacs Lisp style. That's fine with me too. There are a lot of people who are like, you know, it's got too many emojis in it, I'm not going to read that. I'm going to focus my time reading something else that's been handcrafted and all that stuff. That's fine too. There's room for all sorts of people and all sorts of approaches to this. Sometimes even just the idea of something is already valuable, that valuable, that somebody thought of saying, hey, my workflow would be better if it could just do this. If there's a screenshot, even better, right? You can see how it works. Screenshot or video or animated GIF. Because then they can go and write the code that they would have to do anyway. Because of course, they've got their own personalized setup. You know, the code that you write will not mesh perfectly with their particular setup. There's this whole
 There's this Lisp curse essay that's sort of related to


Matei: I was going to ask you about that.

Sacha: We've all got our ecosystems of our own code and absorbing something into it is sometimes hard. But if you start with even just the idea that somebody else has written about, whether or not you take their actual code for it or use their code as a building block, that is already useful and interesting. Again, you don't have to be Bozhidar Batsov or Omar Antolin to be able to contribute at that level. Even at the beginner level, you could just be like, I just need to do this thing and it's driving me crazy to do it manually all the time. Then I'm like, you can do that non-manually? Oh yeah, we should do that.

Matei: Cool. Just to come back to the question about talking to other people about Emacs, do you ever talk to people who are not programmers?

Do you ever talk to family and friends about Emacs?

Matei: Do you ever talk to family and friends about Emacs? Do you ever have to explain what this thing is that you're doing or do you just not?

Sacha: Well, my kiddo is 10, and she's like, can you set me up a kid Emacs? Because she sees me like... Yes! Clearly something of great interest to me. I said, maybe. She does a little bit of vibe coding with Claude as she generates interactive stories. She was trying to track down a syntax error at some point. I was like, can I just install Emacs on your computer so I can do... And she said no. My husband uses Vim. Org Mode at some point, so he found the appropriate Vim plug-in for it. That was amazing. I don't talk to people about editor choices. I just do the stuff that I do. When I write about it, sometimes people will come across it, again, coming from completely different backgrounds. They'll be like, oh yeah, I also need to edit transcripts. What is this Emacs thing? And I'm like, well, it's a very long road, but it's a lot of fun and it's worth it. If you do want to get into it, here's some ways to get started. I don't know. But you can look at the videos first to see whether it might be something that resonates with you.

Matei: Yeah. No, I'm the same. I'm very cautious. I've seen that. The learning curve thing is so cool. My kids are like, your computer used to be so pretty when it was a Mac and now it just looks really ugly. I'm like, oh, if you knew. It's so much more beautiful now, but never mind. Cool. We've talked a lot about AI actually already.

Do you ever use AI in chatbots for anything else?

Matei: Do you ever use AI in chatbots for anything else?

Sacha: Well, I'm learning French at the moment. In this case, the kind of the regression to the mean that AI does is very useful for me because I need to know, what is the common word choice here? How do I get the grammar to do the thing? I don't really want to spend an hour of a relatively expensive tutor's time picking apart my subject-verb agreement or my nouns agreeing in plurality with the verbs and stuff like that. It's reasonably acceptable to use large language models for language feedback. That makes sense. In terms of coding, I'm not there yet. Quite a few people are very enthusiastic about it. Even in Emacs, some people are like, "I don't write my code anymore. I just vibe the whole thing." I love the way that it gets a lot of people to make things that they would not otherwise have the time or effort or experience to do, but on the other hand also, it hallucinates a lot of things. It gets me excited: oh there's a variable or function specifically for this? No! It doesn't exist. I can make it exist, so it's a little less frustrating for me, because I can say, you know, that does make sense. I can write that. I can fill in the blanks for it. But 9 times out of 10, I'll be like, no, no, go back and do the proper search. One out of 10 times, it'll tell me, oh yeah, there is this function and it will exist, exist, then I'm like, okay, great, I want to use that, because I wouldn't have otherwise come across it. But I cannot use it to generate a lot of code because I get this urge to just rewrite things to fit the way I want. I just use it like
 it suggests ideas. It acts kind of like a search engine that gets things wrong most of the time. I'll just take the interesting parts of that and do it myself. Aside from that, I haven't really dug into it to the extent that other people have. I am happy to take a step back and see how this all shakes out because with the shake-up in pricing and all the externalized costs that are slowly being factored in, I'm not going to build a house of cards on it.

Matei: Yeah, that's very wise, I think. How do you feel about the fact that these models have been trained on all these free conversations? They just suck up all this stuff that people have been doing for 40 years. Is that a problem in and of itself?

Sacha: It's interesting in the particular case of Emacs. As I mentioned, the vast majority of Emacs Lisp is released under either the GPL or the MIT license or even public domain because people in Emacs really care about sharing stuff and they want other people to do it. It's not like, oh, we've got this proprietary code and it's been stolen away from us, it's us, it's not available for other people. The fact that we're treating AI-generated code as non-copyrightable, it's okay that it's sort of out there. It would be nice to be able to say, hey, this stuff is GPL, so if you're going to build on it, please share it under the same licenses. But in terms of the way that many people use it for personal configuration and learning, I'm okay with that. I know that other people in the community have stronger stances, and that's also okay. Because there's no attribution, there's no link back to the person. The licensing doesn't require [lots of] attribution. You don't have to say, oh yeah, this config was inspired by these people and at these links. You don't have to do that, but it would be nice to be able to follow those links back to the people. That would be nice. The ability for more people to learn from this stuff is good. If we can encourage them to share what they're figuring out with other people, that's also good.

Matei: So is the problem less about kind of taking intellectual property and more about

Not breaking connections to people

Matei: breaking connections to people or like breaking these traceable connections to other people in the community?

Sacha: That's the part that I'm interested in and care about, because I feel the community experience of Emacs is very interesting. All the other stuff, there are people who are far smarter than me and have focused on... This is above my pay grade, right? Actually working out intellectual property, what that means. A lot of people think about copyright and copyleft and that stuff. I will leave that to them to sort all of the ethics after that one. I just care about making sure people can feel like they're learning, feel like they're welcome, and can find the ways forward both with assistance of large language models if they want to, but also connecting with real people who they can learn from too.

Matei: Yeah, super. I think that's sort of the questions I had, really. I'm sure I'm going to have a million other questions. I might email you back about this. Did you have any questions for me?

Education and ethics and eureka

Sacha: I love now knowing that you were writing your manifesto with that experience of being an Emacs user in mind, because the way that the education and ethics and eureka was like, that actually lines up precisely with the Emacs community and what it's like and what we care about. I would love to explore this in future conversations and see how we can help people navigate this time. There's a lot of froth about AI, and the business world is losing their heads over this collectively. The programmers in industry either find it useful but also, in general, seem to have a fairly worse experience. This is not where we should be using this. This is not how this is supposed to be turning out. It should not be leading to more unhappiness, but it is. It would be interesting to sort out both in the society level, but also in the individual level, as people make their own choices about what to use and how much to use it for, and also the impact, even if they're not making those choices themselves. I think the general sense now, for at least Emacs and Org Mode, is "we're not going to accept LLM-generated contributions because we've got to have a person who can stand behind the code." We so far have been safe from the inundation of generated pull requests that are plaguing other open source projects. It's definitely something to watch out for. But there is some tension. People are proud of their vibe-coded projects, but on the other hand, people are like, well, it takes 5 minutes or 15 minutes to generate this, and because it's not really maintainable, people will lose interest in it after their 15 minutes of fame on Reddit with their nice screenshots and all that. It's not going to keep moving forward.

Matei: Is that kind of like a
 version of the Curse of Lisp written large? Everyone's just going to write their own programs at home and no one's going to be talking to each other anymore.

Sacha: It is very similar to that. that. It can be a problem. It can be an opportunity. It's not one or the other yet. We're figuring out as a community and as individuals how to navigate this. We have this long history of people not actually being able to adopt to adopt someone else's code off the shelf. It's amazing when someone actually puts together a package that can cut across a large variety of use cases. It takes a lot of work to get there, but things like Magit and Org Mode, how do these things happen? Yeah, it's fantastic. I love the fact that we can look at things like consult and vertico... The fact that they can work for a lot of people is amazing. It's actually pretty rare in the Emacs community. But for the most part, we are in our little fiefdoms and we have to make an effort to do that kind of connection. Whether or not the other person is using vibe-coded code doesn't matter that much. There's still that barrier. Higher barrier if you're dealing with vibe code because they don't understand it and you don't understand it and the code is hard to read. The ideas can be transmitted over blog posts and videos. But at the same time, the fact that more people like you can use this to start to experience the power of Emacs, the customizability of it, and can then go on to imagine, hey, is this what software could be? Can it be personal? Can it be malleable? Can I say, "No company is going to anticipate this particular need, but I can make it for myself."? I think that's really worth it. If the tools will help us get there, and if we can find our own balance of ethics that are okay with this... Some people might say, no, definitely not for me, even if it gives me the power. Some people were like, I just want to get this stuff working. That's cool, too. We get to see how that all works out.

Matei: It's interesting. I've written this paper for which I gave a talk in Oxford a couple of weeks ago about this, really for anthropologists. It's anthropologists. It's very interesting that a lot of the things we were talking about today, I thought that might be the case on some of these things. It's partly thinking about the way in which AI, ChatGPT, whatever, kind of interferes, becomes like a broker between the community and the individual. So the good side of it is that you're never going to be told to go and read the manual, right? It's always going to say, "Yeah, sure, that's great." But the bad thing is, you're never going to go and read the manual. That's the problem, right? But what I said at the end of it and I don't know whether this resonates at all, but I said now that I'm becoming aware that this is a problem, the paradox that I got into Emacs for the community and yet, in a way, I'm being moved away from the community. Increasingly, now, I will ask not "write this code for me" but "explain to me why this code doesn't work" or "explain to me why my problem could be done differently," and even more than that, not even "explain to me this" but "suggest to me how I could post this on a forum." I'm a bit worried about posting on a forum in case someone turns around and says, that's stupid. Claude or someone can say, if you write it like that, some people might find it interesting. Does that feel like a different kind of use of AI maybe?

Sacha: It does, and I encourage the more reflective use of it. For example, you might say, instead of generating this code, you might say, can you help me figure out what it is that I actually want to have in my workflow? Can you ask me questions to help me figure out how to do this or how to break it down into smaller tasks? Then that might be a more useful way of doing it. Sometimes people respond better when something is asking them questions. That is possibly an interesting use of AI.

Matei: Amazing. Sacha, thank you so much for your time.

Future conversations

Matei: Having had this conversation, do you think there's matter here for some kind of live stream or something, maybe with other people who want to talk about this stuff?

Sacha: In fact, if you wanted to take this recording and plop it somewhere public, I am totally fine with that. Learning out loud is how we have these conversations grow, right? The conversation is like this brain dump of ideas, and if we want to start unpacking those ideas and exploring them through all the multifaceted perspectives that we have in the Emacs community, other anthropologists or people who are interested in the philosophy of it, there's people who have so much deep experience in things that I have no idea. I would love for them to be able to say, let's take this facet of this conversation and build on it and explore that one. I am totally okay with both sharing this conversation, if you want to, as well as having other conversations that other people might be able to ripple out from.

Matei: Fantastic. I mentioned to Protesilaos that we're going to have this chat, and he said, you know, if you want to at some point organize a discussion over this kind of stuff, he'd be very happy to be involved.

Sacha: I've been experimenting with making myself ask people for help. Prot has coaching sessions. If our schedules can line up, then I can schedule a three-way conversation. It can be live and we can build on the ideas that you might have or follow-up questions that you might have, and then we can see if other people do as well. So that could be good. I'm looking forward to hearing about your insights. I would love to see where this goes. I think the Emacs community is definitely worth studying. I think that there are insights here that you might not otherwise come across in more specialized, more focused... Like, just developers or whatever, or more focused on closed source. There's something interesting about this mix of Emacs and AI and plain text and all that stuff. I would love to see where this goes.

Matei: Amazing. Thank you very much.

Sacha: All right. Bye.

Matei: Bye.

View Org source for this post

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

-1:-- Transcript of chat with Matei Candea about Emacs and AI (Post Sacha Chua)--L0--C0--2026-06-01T19:28:55.000Z

Sacha Chua: Emacs Carnival May 2026 wrap-up: "May I recommend..."

: Thanks to everyone who participated! I've included the links below.

It's May and I like puns, so I'm going to suggest "May I recommend
" as our Emacs Carnival theme this month, building on lively conversations about people's favourite packages on lobste.rs, Reddit, and Hacker News. Let's go beyond packages and talk workflows, tips, practices, perspectives
 whatever you'd recommend!

It was pretty nice having a wiki page that people could edit without needing to wait for me, so if you write about this topic, feel free to edit the wiki page and add your link. If you run into problems doing that, please e-mail me and I can add the link for you.

People have already started sharing their recommendations:

(Still got ideas, just a bit late? Let me know and I can add it here as well as to Emacs News!)

View Org source for this post

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

-1:-- Emacs Carnival May 2026 wrap-up: "May I recommend..." (Post Sacha Chua)--L0--C0--2026-06-01T16:50:38.000Z

Irreal: My Growing Appreciation For EWW

A couple of weeks ago, I wrote about using EWW to avoid paywalls and my experiments to see if it really worked. As I reported, it did in a surprising number of cases. But as I also wrote, I’m not that interested in avoiding paywalls so I didn’t expect to get much out of the experiment other than satisfying my idle curiosity.

It turns out though that I discovered using EWW could be very restful. As I wrote in that last post,

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.

My normal procedure is to read my feeds with Elfeed—the world’s best RSS reader—and to display the original Web page in the same buffer with elfeed-webkit. That gives me a browser like view of the page. The problem is, my ad blocker doesn’t work with elfeed-webkit so I get all the trash and abuse one gets with a default page load1.

During my experiment I discovered that calling EWW when a site gets out of control is an excellent solution. The latest version of elfeed makes this easy so if I site becomes too obnoxious, I simply switch to EWW and invoke eww-readable with R to provide a quiet and restful wall of text (complete with the accompanying pictures).

It’s amazing how much junk we just take for granted when all we want to do is read an article or post. EWW takes away a lot of the sting. No, it’s still not going to replace the browser but it’s an excellent companion to it.

Footnotes:

1

John Gruber has an excellent screed on one part of this default behavior. There are plenty of others.

-1:-- My Growing Appreciation For EWW (Post Irreal)--L0--C0--2026-06-01T15:13:44.000Z

Sacha Chua: 2026-06-01 Emacs news

There were 17 posts in the in the May carnival topic "May I recommend", very cool! Looking for something to write about next? Check out the June theme Underappreciated Emacs Built-ins hosted by Ross A. Baker.

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-06-01 Emacs news (Post Sacha Chua)--L0--C0--2026-06-01T13:56:44.000Z

Tim Heaney: Ziglings

I just completed Ziglings! It's wicked fun! Zig is a programming language and Ziglings is a collection of fun exercises to help you learn it. I heard about if from this interview with Andrew Kelley. He is the creator of Zig (but not the creator of Ziglings, that's Dave Gauer). Zig is still under development (it has yet to release version 1.0), so it's changing a lot and Ziglings is changing right along with it.
-1:-- Ziglings (Post Tim Heaney)--L0--C0--2026-06-01T00:00:00.000Z

TAONAW - Emacs and Org Mode: Installing Harper on Kubuntu: The Right Way. Maybe.

I recently installed Harper on my Linux Desktop to work with Emacs, but since I’m running Kubuntu, I ran into difficulties. In short, there’s no Flatpak or Apt option when it comes to Harper.

After a few interesting changes to the way I journal in Emacs (this is something I hope to discuss soon), I decided to go for the full version, and that meant installing Rust and Cargo.

This was another “programming quest” I didn’t know how to start in the past. I used Claude.ai to guide me, but as usual, I asked a million questions about everything, so I can explain it again here (this is my test to myself). So if you’re new to all of this like I am, take the explanations with a grain of salt, and if you’re an experienced developer who understands Rust (and curl, for that matter) feel free to reach out and educate me further.

Alright, here we go:

To install Rust and Cargo with it:

    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

The above is a bit more complex than what’s in Cargo’s documentation, but based on a quick search, it is what’s directly recommended in rustup, which is where you install Rust. The idea is the same as other curl installations, with a few more options for added security and to ensure we’re getting what we really want:

Run curl, but restrict it only to https (no http):

curl --proto '=https'

Somewhat redundant: curl will usually refuse anything lower than 1.2 by default. This forces TLS 1.2 as the minimum. This is good practice and also what they tell us to use, so why not:

--tlsv1.2

options for silent mode s (so don’t show us progress and status), but show us if we get errors S, and if we get a 404 error or similar, just stop silently f (otherwise it will pipe it into the sh command at the end):

-sSf

Then we have the URL to download from:

https://sh.rustup.rs

and finally we pipe it | into a shell sh command so it runs as a script as intended here. If you go to the above URL directly, it will download a shell script - so this is how we get it and run it in one go:

| sh

Because we’re about to run commands for Rust, it’s a good idea to add it to our source environment, the same as editing ~/.bashrc manually and adding . "$HOME/.cargo/env". Without it, we’ll have to specify where Cargo is installed for the next commands

    source ~/.bashrc

At first, I installed what was available on crates.io. Crates, as I learned, is the official repository for Cargo, our “app store” for Rust, (or Elpa for Emacs). The individual packages are called “crates”. Makes sense now, but before it all looked like a bunch of command-line voodoo to me.

However, apperently what’s available on Crates is not up to snuff. The official repository for Harper is at https://github.com/Automattic/harper, and it specifies version 2.3.1, whereas the one available in Crates is 2.0.0. We are still using cargo (it’s the “installer” for Rust), but specify to get what we need directly from there:

    cargo install --git https://github.com/Automattic/harper harper-ls --locked

The git option tells Cargo we’re installing directly with git, which is what we’re doing here; the locked option is specified in Harper’s documentation, and upon some research, I learned this forces the exact dependency versions specified in Cargo.lock. Without it, cargo might choose newer dependency versions that were not tested or are not specified in the documentation.

Finally, in Emacs, we want to tell eglot where to find Harper:

    (when (eq system-type 'gnu/linux)
      (add-to-list 'exec-path (expand-file-name "~/.cargo/bin")))

In my case, since I use the same config on my Mac, I want this to run only on Linux. On my Mac, Harper is installed without all these shenanigans directly from Homebrew, which also keeps it up to date. This is added to the same config block I specified in my earlier post. It now looks like this:

            (with-eval-after-load 'eglot
              (add-to-list 'eglot-server-programs
                           '(org-mode . ("harper-ls" "--stdio"))))
    
             (setq-default eglot-workspace-configuration
                        '(:harper-ls (:dialect "American" :linters (:LongSentences :json-false :AvoidCurses :json-false))))

      ;; Besides choosing American as the language, I also want to ignore long sentences (the main issue is that it hides other errors nested in those), and I also want Harper not to tell me when it thinks something is offensive. I'm a big boy/an old fart. The full list of these options is in https://writewithharper.com/docs/rules. It needs to be nested inside the :linters option.
    
    (when (eq system-type 'gnu/linux)
      (add-to-list 'exec-path (expand-file-name "~/.cargo/bin")))

In the future, when I need to update:

    cargo install --git https://github.com/Automattic/harper harper-ls --locked

Now, Harper works as it should on my Linux Desktop. Another geeky weekend project.

-1:-- Installing Harper on Kubuntu: The Right Way. Maybe. (Post TAONAW - Emacs and Org Mode)--L0--C0--2026-05-31T22:41:31.000Z

Sacha Chua: Karthik's notes on Emacs Chat 24: Omar Antolin Camarena

Here's a guest post from Karthik Chikmagalur in response to Emacs Chat 24: Omar Antolin Camarena.

  • 16:00 - Omar's embark-on-last-message is gold! I implemented it and have already used it a dozen times in an hour.
  • 17:00 - Omar mentions his tmp package for creating throwaway buffers. I use the scratch package for this. M-x scratch will open up a scratch buffer. If you had a region selected, that will be copied to the scratch buffer. By default, it will use the same major mode as the buffer you calling it from. Calling M-x scratch with a prefix arg will let you pick the major mode you want.

    I have some additional customizations to try to automagically pick a major mode based on what I have selected: https://github.com/karthink/.emacs.d/blob/3deed38c0e02e95fdfab6812c494b1736b945a1e/lisp/utilities.el#L36

    Also related is the edit-indirect package, which I'm sure you're aware of. I think of it as scratch's dual: scratch is for when I want to edit something without regard to its provenance, edit-indirect is for editing the source (exactly like org-edit-special).

    I also try to automagically guess which major mode a piece of text should be edited in. edit-indirect edits something that looks like a lisp form in lisp-interaction-mode, even if the origin is (say) this email composition buffer: https://github.com/karthink/.emacs.d/blob/3deed38c0e02e95fdfab6812c494b1736b945a1e/lisp/utilities.el#L67

  • 21:20 - You mention that you sometimes want to insert something into the minibuffer when you're in the minibuffer, but you end up inserting into the main buffer instead. Omar agreed that there is no easy fix for this.

    Omar, Daniel Mendler and I actually discussed this years ago and came up with a separate command to do this:

    (defun minibuffer-replace-input (&optional arg)
      "Replace original minibuffer input.
    
    When a recursive minibuffer is active, insert the current string
    into the original minibuffer input.  With prefix ARG, replace it
    instead."
      (interactive "P")
      (when (and (minibufferp) (> (minibuffer-depth) 1))
        (let* ((replacement (minibuffer-contents)))
          (unwind-protect (minibuffer-quit-recursive-edit)
            (run-at-time 0 nil
                         (lambda (rep)
                           (when arg (delete-minibuffer-contents))
                           (insert rep)
                           (pulse-momentary-highlight-one-line))
                         replacement)))))
    

    I don't need it every day, but when I do it's very handy.

  • 29:40 - Omar mentions that he prefers to have lots of commands to mark specific text objects instead of hammering expand-region (or expreg-expand). There is a (now) old package called easy-kill which does this, allowing you to define marking commands for different objects at point (e.g. s for sexp, w for word, l for line, d for defun etc). It's easy to add support for more objects because I think it integrates with thing-at-point. The marking command provided by this package is actually called easy-mark.

    But easy-kill / easy-mark is actually the best of both marking styles, because you can use SPC to cycle between marking all the different text objects at point. I've further integrated this with expand-region so that at any point in the easy-kill mark process I can expand the region as well: https://github.com/karthink/.emacs.d/blob/3deed38c0e02e95fdfab6812c494b1736b945a1e/lisp/setup-editing-extra.el#L250

  • 36:00 - Didn't know Omar is the reason vertico-grid-mode exists. That's fortunate, I use it all the time!
  • 44:00 - Omar's point about improving ffap to improve Embark's default action on files is great, really speaks to my sensibilities about composing features in Emacs in a way that provides multiplicative benefits.
  • 48:00 - NOPE! I use CANCELLED as a TODO kwd in Org, but the fact that it's not 4 letters long has bothered me forever. NOPE is much better.
  • 58:30 - Re: Omar's toggle map: this is something I think many users end up writing? Mine is a transient map: toggle-modes-transient.png that grows extra columns in specific major-modes: toggle-modes-full-transient.png

    But I appreciate that Omar uses a regular keymap instead of a visual menu, that's the Embark way. Transient menus are frustratingly non-composable with other Emacs features.

  • 1:00:00 - isearch-delete-wrong is actually built-into ISearch? Pressing C-g once should delete the non-matching part. It's possible he's customized C-g to quit Isearch right away.
  • 1:07:30 - I didn't understand Omar's practice of using embark-dwim to preview the result of any minibuffer command, like org-ql-find. Is this something you were able to reproduce?
    • I've been using dot-mode for almost as long as Emacs, to the point where I've often made the mistake of assuming it was an included feature. It uses simple heuristics, but works surprisingly well at capturing your intent on what the "bounds of an edit" should be in Emacs.
    • Omar mentioned that he stopped using multiple-cursors because the immediate feedback from all cursors inspired false confidence, as off-screen cursors could do something unexpected. I use a personal fork of a package called macrursors that's somewhere in between multiple-cursors and keyboard macros:

      https://github.com/corytertel/macrursors Fork: https://github.com/karthink/macrursors

      It's inspired by both multiple-cursors and meow's beacon-mode. It places cursors at the locations where the keyboard macro will be executed, but executes the full keyboard macro at each location at once, without immediate updates. This addresses the "false confidence" issue, but it does three other things that are very handy:

      • You can bound the region inside which cursors should be placed. The scope can be the paragraph, like in Omar's example, but also any other text object (defun, line etc), and you can cycle between the scopes or expand it with expand-region.
      • You can place cursors from most common actions, like at ISearch or Avy candidates (selectively or all at once), or at all text objects of a certain type inside the bounds.
      • You can "narrow" the buffer to only the cursor locations, fitting and verifying more of them on screen. When the macro runs, the selective display in the buffer persists for a second so you can scan the results:

        https://share.karthinks.com/macrursors-isearch-hideshow-demo.mp4

        Steps:

        1. Start ISearch and search for cl-defmethod
        2. Create cursors from all ISearch matches
        3. Selectively display only the cursors
        4. Show more context around the cursors
        5. Make a change (involving a kmacro counter)
        6. Finish. (The selective display persists for a second.)
        7. Examine the changes.

      It uses undo amalgamation by default so you can undo all the cursor changes except the original one in one step. Of course, your changes are stored in the kmacro ring so you can now apply them as regular keyboard macros too.

      Most of these features are probably present in multiple-cursors at this point, although I'm not sure about bounding cursor ranges with macrursors-select. But this has replaced the usual keyboard macro workflow for me, and not many people are aware of macrursors so I thought I'd mention it.

Thanks to Karthik for his notes! If you have any comments, please feel free to email him.

View Org source for this post

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

-1:-- Karthik's notes on Emacs Chat 24: Omar Antolin Camarena (Post Sacha Chua)--L0--C0--2026-05-31T22:35:02.000Z

Mike Zamansky: Giant - Antisemitism, antizionism, and Roald Dahl

https://upload.wikimedia.org/wikipedia/en/5/57/GiantPlayPoster.png
Giant

This past Friday, I had the chance to see "Giant," the play written by Mark Rosenblatt. A few friends asked for my take on social media so I thought I'd write my thoughts up here.

So, if you're looking for the usual CS Ed or Emacs material, feel free to skip this one. On the other hand, I'd encourage you to read on anyway.

First and foremost, the play was fantastic. John Lithgow was fantastic and Ava Cash was his match. The rest of the cast was solid overall and I could hear thoughtful discussion around me during the intermission and I personally wanted to let everything stew for a couple of days before writing this.

If you're in NYC and have a chance - see this play.

In 1983, children's author Roald Dahl wrote a review of the picture book "God Cried." In it, he wrote a number of antisemitic slurs. The play is a fictionalized account of an afternoon at Dahl's new house (under construction) where he met with publishers. The topic was what, if anything should be done about the review, the ensuing push back and the fact that Dahl's latest book "The Witches" as due to be published soon after.

To fully paint the context here, Dahl was, by his own admission an antisemite and we'll get to a bit of that later. He also publicly released antisemitic statements after the original review that set the stage for this play. In fact, the play closes quoting some of those statements via a call between Dahl and a reporter. In 2020, his family released an apology.

Even though the play first ran after the October 7 attacks, it was finalized prior and to my knowledge unchanged as a results of the attacks or the ensuing war.

The cast:

Roald Dahl
John Lithgow
Filicity Crosland
Rachael Stirling - Dahl's mistress, fiance, and later wife.
Tom Maschler
Elliot Levey - Executive at Dahl's publishing company. England based. A Jew who's family fled Vienna after Nazi annexation when he was five.
Jessie Stone
Aya Cash - Sales employee of Dahl's publishing company. Also Jewish. Based in America.
Hallie
Stella Everett - Domestic employee of the Dahl's
Wally Suanders
David Manis - Groundskeeper for the Dahl's.

While the meeting depicted in the play was fictional, Dahl, Crosland, and Maschler did indeed exist though I have no idea if Crosland or Maschler's depictions were in any was based in their real personalities. Stone was created for the play and I'm not sure about the last two.

In the early stages, Maschler and Stone are trying to convince Dahl to publish a statement - an apology for his comments and Dahl refuses. Maschler, in spite of being a holocaust survivor, is playing the role of the "good Jew" - he said he was just "put on a train" that he was a child. He's assimilated and seems to want to "go along to get along." His concern is all about Dahl's reputation and selling book. The antisemitism doesn't phase him in the least.

Stone on the other hand, an American Jew, sees things differently. While initially towing the line she can't contain herself and calls it like she see it. At the end of the first act, Stone quotes from Dahl's review emphasizing where he calls out Israel's actions but refers to them as the actions of an entire race not of individuals nor a specific government. It was a powerful scene and what likely led to a lot of the intermission discussion in the audience.

In act 2, Maschler continues to try to be the "good Jew" but finally breaks, hopefully understanding what Stone got all along.

As to Dahl, he switches between being acerbic and conciliatory making one wonder if he is indeed antisemitic or if he's merely being provocative for the sake of being provocative - playing the role of cantankerous old man. That thought is put to rest at the close of the play as he's on the phone to a reporter who's giving him every opportunity to disavow his original comments only to see Dahl double down.

Of note was a comment made by Dahl, apparently a real quote that he was originally "only" an antizionist but became an antisemite.

This may sound familiar. It's the latest rage "I'm not antisemitic, just antizionist." Of course, Dahl's statement doesn't hold up to scrutiny any more than the current generation's claims as revealed at the close of the play when he talks of the lack of Jews participating in the war and with quotes like "there is a trait in the Jewish character that does provoke animosity. 
 Even a stinker like Hitler didn't just pick on them for no reason."

There's more to the play - does a mans personal beliefs, as twisted as they are devalue his work? What of Hallie, the domestic who's put in an uncomfortable position mid play almost having to either defend or condemn her employer. Was Dahl a child in an adult body - a childish mind giving birth to his worlds in literature but at the same time poisoning his views on reality?

I'm thankful that this play is currently on Broadway and has such an amazing cast. They don't sugarcoat Dahl's antisemitism and there's plenty in the play to expose antizionism for what it is, a cover for Jew hate.

You'll enjoy the performance and if you give it a chance, it'll leave you thinking.

See it if you can.

-1:-- Giant - Antisemitism, antizionism, and Roald Dahl (Post Mike Zamansky)--L0--C0--2026-05-31T15:41:10.000Z

Donovan R.: 💭 My Ancestors Were Writing Lisp

I’ve been hard on Lisp lately.

Last time I wrote here, I called it a curse — a language so powerful that everyone who touches it ends up building their own private dialect, until no one can quite understand anyone else. A small Tower of Babel, assembled out of parentheses. I still think that’s true.

But I left something out of that post, because it didn’t fit the argument I was making. The same Lisp idea that scatters programmers did the opposite thing to me, once. It didn’t scatter anything. It pulled something very old back together.

It gave me back my ancestors.


Let me explain, because it sounds like more than it is.

I’m not a Lisp programmer by trade. I just love the elegance of the thing — I’ve lived inside Emacs for years, written my own Elisp, poked at Clojure enough to feel what makes the family different. And the difference, the one everyone eventually trips over, is this: in Lisp, code and data are the same kind of thing. A list of symbols is information, or it’s a program, depending only on how you choose to read it. Data is code, and code is data.

Most people find that strange. Some find it beautiful. I was sitting with the strangeness of it one evening when something turned over in my head.

The vakana, I realized, were the same shape.

Vakana is our Malagasy word for beads — and there is no other word for them in my language, which tells you something about how old they are. I grew up knowing two things about them. That they were beautiful. And that they were a little frightening — in Madagascar, beads are tangled up with sorcery, and you learn young to keep a respectful distance.

What nobody told me — what I had to go the long way around to see — is that they were also a tool for thinking.

A bead has a form, a surface, a feeling it carries, a mark. Thread a few together and you have a sentence. Wear them in an order and you have a record. Pass them to someone and you have a message. The bead isn’t only worn — it’s read. And it doesn’t only get read; it does: it anchors a memory, marks an intention, names a person, declares a state. A unit that is at once what you say and what you mean. The exact shape a Lisp programmer knows in his fingers.

It was a small thing to notice, structurally. It was a very large thing for what it implied.

the vakana as a system

(Added after a reader asked for a concrete example.)


For most of my education I’d absorbed, without anyone ever saying it out loud, that the practices of my ancestors were aesthetic. Or spiritual. Or symbolic — and sometimes those words were just a polite way of saying not quite serious. The real thinking tools belonged to modernity: the journal, the calendar, the database.

But the vakana are exactly that. My ancestors used them the way I use a journal — to hold what happened, what to remember, what to commit to. The way I use a calendar — to pin meaning to a time and a place. The way an engineer uses a schema — to compose meaning out of a few fixed parts. They wore the whole system on the body, where it could be touched and counted without looking.

What I had been taught to see as ornament was the operating system.


There’s a second half to this, and it’s the half that turned the realization from clever into important.

Malagasy is a language made of pictures, and you hear it most clearly in the way we keep time. We don’t say one-thirty in the morning — we say mitrena ombilahy, the bellowing of the bull. Two in the morning is maneno sahona, when the frogs call. Six in the evening is maty masoandro, the death of the sun. (I wrote about this once: in Malagasy, time is told by what the world is doing, not by a number.) Even the turning of the year was read this way once. The month-names we use today are borrowed Arab zodiac, but the older Malagasy ones were small descriptions of the world — Papangolahy lava elatra, the long winged male Papango, for the season the zodiac calls Aries.

And it isn’t only time. The names themselves are descriptions. A tree can be called Mpanjakaben’ny tany, the great king of the earth; the pomegranate is Apongaben-danitra, heaven’s great drum. A person’s name can be a whole sentence — Andriantsimitoviaminandriandehibe: the noble without equal among the great nobles. To name a thing, in Malagasy, is already to draw it. To think in the language is to think in pictures.

I knew, before I made the connection, how much that matters — because I’d wandered into the Art of Memory. The Memory Palace: the old trick that lets a person hold a whole shuffled deck, or a thousand names, by placing vivid images in remembered rooms. It works because memory is built for image and place far more than for word and order. The Greeks thought they’d discovered it. They were late too.

The classical memory artists knew one more thing — that the kind of image matters. An image that frightens or shocks or moves you sticks; a neutral one slides off. And here is the part that stopped me: the vakana names are already charged that way. Tsileondoza — roughly, disaster cannot undo it — is a bead worn against ruin. The whole intention compressed into one frightening word, carried on the body.

So the fear that follows the beads in Malagasy life — the sorcery, the thing I was taught to keep away from — was never a superstition wrapped around a harmless object. It was the technology working. An emotionally inert bead is a worse memory tool than a charged one. My ancestors built their system out of images that stick, and one of the surest ways to make an image stick is to make it a little dangerous.

It was a cognitive technology. It was also magic. I’ve stopped thinking those two sentences argue with each other.

Not yet another technique. Something bigger. Something stronger. One of the most sophisticated tools for thought any culture has ever produced — and most of us who inherited it have forgotten that this is what it ever was.

Let me not overstate it, though. The art is not dead. The ombiasy — our sages and healers, the keepers of the old knowledge — still hold the vakana, and hold it far more deeply than I do; there are things in it I probably can’t yet fathom. What’s been lost is not the tradition itself but the everyday relation most of us had to it — the way it was once common knowledge and is now a specialist’s, kept by a few while the rest of us learned only to be a little afraid of it.

I’d like that to be known again, by the rest of us. That, honestly, is most of why I’m doing any of this.


Here is what is mine, and what is not.

I didn’t invent the vakana — they’re older than my whole line. I didn’t discover that they form a language, either. That reading came from inside the tradition itself, and it had been set down in serious, scientific study years before I had any interest in note-taking or productivity — before I had even started to learn computer science. It was never mine to claim. And the bead itself was never the genius — the genius was the grammar that could take any object, even a foreign one, and make it carry meaning.

So what’s mine is small, and I want to keep it small. Only this: I happened to be standing in an unlikely spot — Malagasy, in love with Lisp, curious about memory — from which you could see that the bead and the list and the remembered room are the same idea wearing different clothes. That’s the whole of it. I noticed a rhyme. And I’m holding it lightly, the way you should hold any reading that hasn’t yet been proven wrong.


The app came after all of this. Not before.

A few posts ago I told you I was building something, and that I’d write about the journey. This is me, finally writing about it — except I owe you an honest correction. The tool isn’t the one I set out to make.

What I wanted was modest. Last year we planted trees, and I started watching the seasons turn — the jacaranda in flower, the odd little weeds that appear in winter and vanish before you’ve learned their names. I wanted to keep a journal of the plants in my garden: how they grew, what they were called in Malagasy, how my people once used them. Nothing on my phone fit the shape of it, so I started building something that would.

And the moment I did, the vakana insight walked in and asked to be tried. I reached for the bead-grammar almost as an experiment — could it hold a plant, a season, a cycle of growth? It could. And not only that: it held nearly everything else I had ever wanted to write down. I came back holding my ancestors’ beads. The journey took a turn I didn’t choose, and I followed it.

It’s called Vakana.mg, and I want to say plainly what it is and isn’t. It is not the vakana. The system is older than any of us and will outlast the app by a long way. What I’ve built is a working surface for it — a way to practise the grammar every day, on the phone most of us actually live inside, without a string of beads in the pocket. It’s an imperfect translation, because anything digital trying to carry something physical is imperfect. My own memory taught me that years ago, against my preferences: for remembering, the physical always wins.

But even imperfect work bears its fruits. The app lets the practice be kept, and re-read, and handed to someone else. And it lets the vakana be met, for the first time, by people who’d otherwise never hear the word.

If I do this honestly, the app won’t be the destination. It’ll be a door. Some who walk through it will be happy with the digital version. Some will want a real bead in the hand. Some will go and study what the ancestors actually did and bring back more than I ever could. All of that is good, and none of it belongs to me.


Lisp and the vakana turn out to be the same shape — a tiny grammar that composes without end — separated only by centuries and by what they’re made of. And neither of them hands you meaning. Lisp gives you a handful of parentheses and lets you build whatever you want; the bead gives you a handful of forms and lets you mean whatever you need. You can no more read the meaning off a stranger’s beads than off a stranger’s code — and I built the app that way on purpose.

I’ve written here before that you have to seek your own understanding — that no one can do that part for you, however much you’d like them to. The vakana is the same conviction, made into a tool.

Because no one can hand you your meaning, either: not a guru, not even a true elder — and not me. Not because the keepers are frauds; they hold real depth, more than I ever will. But a meaning you were handed, and did not make yourself, won’t hold — and an image you choose is the only kind that does. What an elder can give you, what I can give you, is the grammar: small, and old, and ours, and far stronger than I was taught. The meaning, you write yourself.

I’m building it for the few people who, reading this, will feel a small click of recognition.

It isn’t out yet — vakana.mg just says coming soon, which is honest. If you’d like to know when it’s ready, you can leave your email there.

If that’s you — stick around. I’ll be writing about the journey.

-1:-- 💭 My Ancestors Were Writing Lisp (Post Donovan R.)--L0--C0--2026-05-31T00:00:00.000Z

tusharhero: May I recommend: lesser known org-modes

~373 words. ~1 minutes.

For this month's Emacs carnival topic, May I recommend
, I would like to recommend two cool org minor modes I discovered recently, in the order of me discovering them.

org-num-mode

This mode adds numbering to headings. Like this:

  * 1 heading
 ** 1.1 subheading
 *** 1.1.1 subsubheading
 ** 1.2 subheading
 * 2 heading

This is not added to the text directly, only visually. I believe it is done via overlays.

org-toggle-pretty-entities

This mode converts some TeX markup into the respective UTF-8 symbols, visually (as prettify-mode does). You can get a list of all available entities(symbols) using org-entities-help. BTW, it is also possible to define your own in org-entities-user.

So to give you an idea how of how it looks,

 1_1 a_b^q q_p p^q

Gets prettified into,

1 1 a b q q p p q

Some of you might be wondering, "Why would I use this when I have org-preview?". This is much simpler for when you just need to type a symbol.

Another potential question could be "Why wouldn't I just C-x 8 RET (insert UTF-8 character, for those who are not aware)?", you can't do a superscript q or subscript q, since those symbols don't exist! Which is why I chose q for my demo above.

Also this is way more convenient than C-x 8 RET, and that reminds me, there is a similar feature to this which actually inserts UTF-8 characters into your buffers, C-x RET C-\ TeX RET. Then you just type the TeX markup as you normally would, and it inserts the actual symbols, but this too has the same problems as with directly inserting symbols, some symbols are simply not available.

As a side note: I am sick of having a Unicode character for ☃ and ⛄ but not a superscript and/or subscript for half the letters! Why???

Thankfully, I can just use this mode and type all the q q q I want. Also, org automatically exports it correctly when exporting to HTML!

-1:-- May I recommend: lesser known org-modes (Post tusharhero)--L0--C0--2026-05-30T18:30:00.000Z

Irreal: Reading Gmail In Emacs On macOS

As most of you know, I don’t use Gmail or anything else from Google—except YouTube—if I can help it. They have, sadly, moved from “Don’t be evil” to “Do whatever you need to do to make us money”. For reasons that we here at the Irreal bunker have a hard time understanding, lots of people disagree and are all in on Gmail and many of the other Google offerings.

If you’re one of those Gmail users, are running on a Mac, and are an Emacs user, you may want to read your Gmail from within Emacs. The problem is that it’s difficult to configure Gmail authentication. Yi-Ping Pan has a solution. He uses the Password app instead of OAuth2 and says that you can get everything set up in about 20 minutes. Take a look at his post for the details. He provides everything you need to get things running.

Webframp notes in a comment that Pan’s solution might not work if you have Google’s advance protection enabled. I can’t comment on that because: not a Gmail user.

Well, actually, I suppose that technically I am a Gmail user because I do have a Gmail address. I can’t remember the last time I got any mail from it but irrational paranoia keeps me from deleting it. How, then, do I deal with Gmail? Simple. I forward it do my main email account so that it appears normally without having to do anything special. Like many of you, I have several email accounts and I do the same thing with all of them: I forward them to my main email account. Mu4e makes sure that my answers come from the appropriate email address.

If you’re using Gmail as a secondary account, forwarding it to your main account may make more sense than jumping through Google’s hoops. Regardless, if you want to retrieve Gmail directly, Pan’s post has a good solution.

-1:-- Reading Gmail In Emacs On macOS (Post Irreal)--L0--C0--2026-05-30T14:48:45.000Z

Bicycle for Your Mind: Links of Note 2026-05-30

Kitty!Kitty!

macosxguru at the gmail thingie.

Note: Thanks to Photo by Baku Kerimbekova: https://www.pexels.com/photo/cozy-fluffy-cat-sleeping-on-bed-linen-32157260/

-1:-- Links of Note 2026-05-30 (Post Bicycle for Your Mind)--L0--C0--2026-05-30T07:00:00.000Z

Sacha Chua: Emacs Chat 24: Omar Antolin Camarena

: Updated transcript and added a link to Karthik's notes.

I chatted with Omar AntolĂ­n Camarena about Emacs, keyboard macros, temporary buffers, Embark, and other workflow tips.

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

Related links:

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

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

Chapters

  • 0:00 Ignore this part
  • 0:18 Opening
  • 0:46 How did you get into Emacs in the first place?
  • 6:01 Repeating edits
  • 7:28 dot-mode: repeating commands
  • 9:24 block-undo: undo things as a chunk
  • 10:29 Starting and stopping keyboard macros
  • 12:15 Keycast and Embark
  • 13:33 apply-macro-to-lines-of-paragraph
  • 16:34 embark-on-last-message
  • 18:06 tmp-buffer with a major mode
  • 19:26 placeholder
  • 20:38 enable-recursive-minibuffers
  • 22:57 Overriding embark-select
  • 23:32 quick-calc
  • 26:30 Multiple cursors
  • 27:40 Block-undo and regular undo
  • 28:53 Cycling through Embark targets
  • 31:39 Imenu for navigation
  • 32:51 Collaboration
  • 38:01 Technology adoption and Emacs packages
  • 40:06 Personal packages and naming conventions
  • 42:26 find-file-at-point and directory names
  • 43:49 The value of using Emacs’s APIs
  • 44:56 org-ql and usual files
  • 47:06 Shortcuts for org-ql search syntax
  • 47:43 Org TODO states: TODO, WAIT, DONE, NOPE
  • 48:26 The inserter macro
  • 50:05 luggage: generative art experiments
  • 53:49 Teaching and Emacs
  • 54:53 The print10 generator
  • 56:23 arXiv
  • 58:29 Toggle keymap
  • 1:00:54 isearch-delete-wrong
  • 1:03:14 isearch - continue from the beginning of the match
  • 1:05:12 Using keymaps to remember sets of commands
  • 1:06:04 Other things from the config

Transcript

Expand this to see the transcript and screenshots

0:00 Ignore this part

Sacha: Cut off at, you know, roughly an hour and seven minutes from now. She's going to come out and have lunch. Okay. All right. Going live. Alright folks, we are here a little bit early.

0:18 Opening

Sacha: This is Emacs Chat 24 with Omar Antolin Camarena, whom we know from Embark and Orderless and a lot of other little packages that I personally use on a daily basis. I'm very much looking forward to this conversation.

Omar: Yeah, so am I. Very excited.

Sacha: Of course, before we dive into all these lovely details, tell us a little bit more about your context. You're a researcher at the Mathematics Institute. I can see why Emacs would be a great fit for that.

0:46 How did you get into Emacs in the first place?

Sacha: How did you get into Emacs in the first place?

Omar: I think it's just by virtue of being old. When I started out looking for a text editor, there were not that many great options. When I was a teenager, 30 years ago, I decided to install Linux because I heard about it. That was the era where you went to a newsstand and you bought a Linux magazine that came with a CD, and I installed Linux from that. I think it was Slackware, maybe. I was already a hobby computer programmer. I've been learning programming languages since I was a child, when my father gave me my first computer. I think that was the main reason I switched to Linux. I noticed that people wrote many more interpreters and compilers for Linux than for Windows. That's why I wanted to use Linux. I needed a text editor that handled all sorts of weird programming languages. I was looking for a general purpose one, not an IDE. I used IDEs, younger ones, like Turbo Pascal. Probably that was the main one. I loved that. It was great. I went through the Linux distro, tried a bunch of editors. I settled on Emacs and Emacs-like editors. I tried Jove, which stands for Jonathan's Own Version of Emacs. And there was also an editor called... Oh, I forget. There was one that had its own extension language called S-Lang. I used that for a while. A little later, I remember using Slava Pestov's jEdit. I really like that, too, although Java is not that fun to write extensions in. I was looking for an editor and I wanted it to be extensible, which is funny because I hardly ever extend it. I just wanted there to be the option. I used Emacs for a long time. But when I got serious at being efficient at text-editing, I actually switched to Vim. I switched back to Emacs many years later because of one very specific problem in Vim. The syntax highlighting for LaTeX files is pretty slow. On a normal computer, you won't notice that it's slow. But I had a little netbook that was like 10 years old when I had it. I took it to class to take notes in math courses. I was writing in LaTeX Live with a bunch of macros to insert things. The syntax highlighting meant that Vim lagged behind my typing. I'm not that fast of a typist, so it was problematic. The Vim manual has an entire section on what to do if text highlighting is slow. You can look for it with Vim :help tex-slow That pops up the right section of the manual. I tried everything that it said there and they all made it slightly faster, but none of them really solved the lag, other than turning off syntax highlighting. I turned off syntax highlighting and took notes for like half a semester, and then I decided to try Emacs on that old netbook. Its syntax highlighting was perfectly snappy. This is just a weird thing in Vim that specifically LaTeX syntax highlighting is slow. I never noticed it being slow in any other... I don't know what Vim calls them, what Emacs would call a major mode. It was only ever slow in LaTeX, but that was enough to get me to try Emacs. But by then in Vim, I had learned that you want very granular motion commands to move by word or by sentence, and you want to be able to be placed at the end of the word or at the beginning of the word. All of these higher-level editing constructs that Vim really pushes you toward. In Emacs, I hadn't done any of that before. I moved around with the arrow keys. But when I came back to Emacs after having been in Vim, then I wanted to get serious about editing efficiently in Emacs. I think I actually like it better than Vim now. But yeah, that's why I switched back to Emacs. It's just this quirk that LaTeX syntax highlighting is slow in Vim.

Sacha: Well, their loss. So you tried a whole bunch of other editors. You got into Vim because you wanted to be more efficient. Getting deeply into Vim was great, but you ran into that bug. So you switched to Emacs because it was more efficient, more performant. All that experience with Vim has made you a better Emacs user because now you're like, okay, you appreciate all the navigation and movement. And you were telling me over email...

Omar: Things I missed from Vim.

Sacha: Yeah, You were telling me over email how the kind of the keyboard macros that you got used to in Vim, you've translated some of that over to Emacs and how you use them. We definitely want to get into that.

Omar: Keyboard macro-like things. In Emacs, for a while, I used multiple-cursors. I liked it a lot.

6:01 Repeating edits

Omar: One thing I really missed from Vim is the dot command that repeats the last edit. But in Vim, edits are composite things. You have a command to change a sentence, for example. That will delete the current sentence, put you into insert mode, let you type a new sentence, and when you press escape, that concludes the edit. The whole edit is the operation of deleting the current sentence and replacing it with the specific thing you typed. That is a thing you can repeat. The repeatable edit commands in Vim are much coarser and more conceptually appropriate units than in Emacs. The repeat command repeats the last Emacs command, but everything runs a command in Emacs. You can repeat inserting the last character. That's not very useful. You want to repeat at least the whole consecutive stretch of characters you inserted. Undo in Emacs does do that. Undo coalesces. If you type a bunch of characters and you undo, it doesn't undo them one by one. It undoes them. It clumps them depending on pauses between your typing. That's fine. I want that sort of coarseness. I don't want to undo every single step at a time. Similarly, when you repeat things, you don't want to repeat every single step. I think Vim has like a pretty good unit of things you can repeat. I was missing that in Emacs.

7:28 dot-mode: repeating commands

Omar: There's a package called dot-mode which I used to use and I like a lot. I'm not exactly sure why I stopped using it. So this gives you a more Vim-like experience for repeating commands in Emacs and what it does is that it watches you as you type and it constantly makes a keyboard macro out of the last consecutive stretch of buffer modifying commands. So, for example, in Vim, if you want to change a word, there is a change word command, and you type c w, and then you change the word, and then that thing gets repeated. In Emacs, to change a word, it's not a single unit, right? You delete the word, and then you type in something new, and each character you type is running insert-char. dot-mode will coalesce all of that into a single keyboard macro that you can repeat, right? If you do some motion command that doesn't modify the buffer, and then you delete a word and type a new word, everything from the deletion to the end of the typing would be what dot mode repeats. The experience is actually very similar to using dot in Vim. In my opinion, a little bit better, because in Vim, I often had this problem. It gets you into this competitive video game mentality. How do I do the edit in a single repeatable command? I want to be able to use dot to do this again. So that you have to think ahead. It's kind of distracting. Of course, if a sensible person would not get caught up in that, it would just... do the edit whichever way they can, but I wanted to maximize the repeatability. dot-mode lets you be a little bit more relaxed. It still catches all of the thing that should have been a single edit. So yeah, I like it a lot.

Sacha: So that's dot-mode.

9:24 block-undo: undo things as a chunk

image from video 01:06:05.633Sacha: You also mentioned block-undo.

Omar: That is a package of mine I can show you. That's the entire package. It just uses this with-undo-amalgamate command. Whatever you run inside with-undo-amalgamate undoes in a single step. I use it for executions of keyboard macros. A keyboard macro, if you run it all over the place, if you apply it to every line in a region, or you just repeat it a hundred times, that is a lot of tiny individual edits. If you undo that, you do not want to undo them one by one. This just makes them all undo in a single step, which is what Vim does, actually. This is one of the things that I said, no, Vim has this right. I need this in Emacs.

Sacha: Okay, that makes sense. So dot-mode is more like implicit keyboard macro boundary definitions. This one is like the undo-ness of it.

10:29 Starting and stopping keyboard macros

image from video 00:11:29.533Sacha: I saw in your config, you also have more convenient shortcuts for starting and stopping keyboard macros. It's like a modifier and the keystroke instead of two or like function keys, which are further away. I'm guessing you use keyboard macros a lot.

Omar: Yeah, I do. When I got rid of dot-mode, it was an experiment to see if I could just remember to record keyboard macros. The thing that the dot-mode or the dot command in Vim solves is that you don't always have the foresight to record a keyboard macro. Sometimes you realize, oh, I need to do the same at some other places, but you didn't record it ahead of time. Then you wind up doing it once, realizing you need to do it a bunch of times, then recording the macro, then doing it again. I wanted to see if I could remember to record macros. I decided that I needed to make it as as frictionless as possible. This is the command that is bound by default to F3. I like it better than the thing that's bound to C-x ( because this kmacro-start-macro-or-insert-counter does both things. It could start a recording, or if you are recording, it will insert the keyboard macro counter.

Sacha: For folks who are like, what? Macros? Counters? Yes, you can have your keyboard macro automatically add one to a number, for example. There you go.

image from video 00:12:10.867Sacha: Hello, hello, hello.

12:15 Keycast and Embark

image from video 00:16:44.033Omar: I also activated keycast. I hope people can follow along. I have some small modifications to make embark transparent to keycast. If I use embark, you see embark-act, but then you also see what command I call.

Sacha: I just stole that from your config. I wasn't entirely sure if I was using it correctly, but it definitely looked like something interesting and useful.

Omar: If you don't use that change, then keycast doesn't see through embark and you don't get which actions you called.

Sacha: Yeah, the opacity of some of these kind of key binding niceties... they hide a lot of stuff from the standard Emacs ways of doing things. That's one of the criticisms of transient and other tools. I'm glad that you're finding these ways to make these packages work well with other packages.

Omar: I think this was by request. Somebody requested it. Maybe it was Prot. It's definitely a good idea. The code for that is on the Embark Wiki as well.

13:33 apply-macro-to-lines-of-paragraph

Sacha: The other thing that I wanted to point out that you make a convenient keyboard shortcut for in terms of keyboard macros is apply-macro-to-lines-of-paragraph, which I personally had not been using until I saw your config. And I was like, that is a thing.

Omar: Yeah. Well, that's a command that I wrote. It’s a wrapper around apply-macro-to-region-lines, but it automatically uses the paragraph. That way you don't need to select it. I find that extremely convenient. What would be a good example of that? You want to wrap something. What should I do as an example of this? For some reason, I needed to convert these things to, say, unwrap the parentheses and turn them into an Org Mode table.

Sacha: Yeah, that makes sense.

Omar: I just apply it to the rest of the paragraph.

Sacha: Magic. That's great, because I would normally just start executing the macro and hope I remember to stop at the end, but then I overshoot, and then I have to undo, j and then it's a mess.

Omar: Or you could select the paragraph and then just use the built-in apply-macro-to-lines-in-region.

Sacha: Yes, yes, that's a possibility.

Omar: It just saves you the step of marking the paragraph. I found that I most often when I used apply macro to lines in region, the region was exactly a paragraph. So I figured like there's no point in...

Sacha: All right, all right.

Omar: It's undone in a single step. Like the application. The thing I recorded as a macro, that is not coalesced. Yes, of course.

Sacha: Because that's the actual recording of it. Charlie Baker in the chat says, "Definitely going to add the keycast transparency to my config. I've been wanting that for a while." These little demos of like, oh, this is what this thing in your config does. It's very helpful for people to be able to see its awesomeness.

Omar: Where is that?

Sacha: One of the other interesting things you mentioned was your placeholder package. I can see how the keyword macros help you with text that's already there. Then you've got these placeholders for informal snippets or quick snippets. Show us that. You use it a lot.

Omar: Yeah, I do. Oh, that tmp-buffer is a command I have for popping up temporary buffers in specific major modes. Maybe I can quickly show that first. Yeah, yeah, yeah. So let's see. Oh, yeah. So let me...

16:34 embark-on-last-message

Omar: There I used another little command I have. embark-on-last-message It just calls Embark on the last thing in the messages buffer. Often I want to act on the thing that is the last word in the echo area, so that's what this does.

Sacha: Okay.

Omar: The last thing in the echo area was this symbol embark-on-last-message so I can act on it directly.

Sacha: Which is brilliant because I keep switching to the messages buffer to try to copy something, and by the time I switch, sometimes there are other messages, so it's great to just be able to do something.

Omar: If there are other messages, then I also switch to the messages buffer, but if I want to act on the very last thing, I have that command for it.

Sacha: Yeah. I'm saying this is faster, so I get the chance of just hitting the shortcut before another timer goes in and messes around with my messages. So yes, shortcuts. Okay, temp buffer. Tell us about that.

Omar: You can configure single... Wait, where am I? Transcribing job. I ran Whisper by accident.

Sacha: Which is another thing I wanted to check. Many things I want to talk to you about


Omar: The idea of using Whisper, I stole from you using it to dictate. I thought, oh, this looks convenient if the model is good. I tried it and it is very good.

18:06 tmp-buffer with a major mode

image from video 00:18:10.233Sacha: Temp buffer.

Omar: Different major modes. It has a customizable list of bindings for specific major modes.

image from video 00:18:19.533Omar: It also has an option to just prompt you for a major mode. It pops up a temp buffer in whatever major mode you chose. I use it all the time to make new scratch buffers.

Sacha: Yeah, I can see that's useful. I switch to a buffer that's got a name that doesn't exist yet, and then I have to press more keys to get to the major mode.

Omar: But if you're doing certain things, just type random letters to make a new buffer, this is much better. They might as well all be called temp.

Sacha: Do you reuse the buffers, or it's always just the one buffer?

Omar: New buffer, then I kill it.

Sacha: Very temporary. Gotcha.

Omar: By the way, kill-current-buffer doesn’t have a default key binding. I don't understand why not. OK. I bind it to C-c C-k, which normally, I think, is kill-buffer, but why would you want to kill a buffer that's not the one you're looking at? Wait, what was I going to show you?

Sacha: You were going to show me placeholders.

Omar: Right.

19:26 placeholder

image from video 00:19:42.100Omar: I often need to send several similar email messages. I'm going to invite you on some day of some month to give a talk, etc. That's the body of an email. I'll write it once. Here I’m using placeholder-insert to insert this symbol. It appears in green, but it doesn't matter. It's just text. You could type that symbol yourself.

image from video 00:20:05.633Omar: Then the placeholder-next and -previous commands will cycle among those and let you fill each one in. You don't have to fill it in right now. If you repeat the command, it restores the placeholder and moves you to the next location.

Sacha: That's one of the things I liked about the implementation compared to yasnippet, because yasnippet, you’ve got to actually remember to fill in the fields before you move on to something else. If you get out of it, you can't tab to the next field. The placeholders will let you go and come back and look up some information and put that in and so forth.

20:38 enable-recursive-minibuffers

Omar: Yeah, there's lots of things I loved about Vim, but one thing I grew to strongly dislike is modal computer programs. Not just modal editing, modal anything. I don't like being forced to finish what I started. I want to be able to get distracted and go off and do something else. For example, in Emacs, I very much dislike the default value of enable-recursive-minibuffers. The default value is nil. They don't let you use the minibuffer if you're already using the minibuffer. Emacs is supposed to be about freedom. Why is that the default value? So I set it to t, which is more sensible. That way you're not stuck in the minibuffer.

Sacha: Actually, one of the things that I've been trying to figure out is when I'm in a minibuffer, sometimes I want to use Embark to insert something into the minibuffer, but then I end up inserting it into the buffer buffer.

Omar: Yeah, there's no... Embark doesn't have any solution to that problem. It doesn't always do that. It does that if you're in the minibuffer in a completion session. If you're in the minibuffer in a non-completion session, then it acts as a regular buffer. So if you're in eval and here you had... You can use embark-insert in the usual way to duplicate stuff.

Sacha: I have a workaround. I just use kill. I copy the text instead of inserting it and that works out fine.

Omar: Yeah, I do too. The behavior of inserting into the previous buffer is so useful that I don't think I would want to change that. But yeah, it is unfortunate that for that specific instance, you can't use insert.

Sacha: I appreciate that Embark allows us to have all of these key bindings that we can do stuff with. I noticed in your config, in addition to Embark, you also modify a lot of the standard key maps to add other shortcuts to rebind things that make sense to you. Key bindings are something that a lot of people struggle with, trying to figure out more places to put more shortcuts that make sense. What are the key shortcuts that work really well for you?

22:57 Overriding embark-select

image from video 00:23:18.367Omar: One thing I don't like about the default Embark configuration is that SPC is used for embark-select, which marks a target for later use. I hardly ever use embark-select, so I would rather SPCbe for marking the region, which is something I do pretty often, and have embark-select on C-SPC, which is not a command I use very often. I swapped those. I think most of this is just adding new actions that feel specific to me.

23:32 quick-calc

image from video 00:24:05.733Omar: quick-calc is the thing usually found to C-x *
 calc-dispatch is the command. It’s C-x * q. That’s quick-calc. It's useful as an Embark action. If you have an expression and you... Wait, what am I doing wrong? I forgot what my binding to mark what Vim calls a word in capital letters, which means a consecutive stretch of non-space characters... If you mark this, I can act on it with =, get the result.

Sacha: And specifically this embark-region-map is what you can add in the selected region. Incidentally, I've been playing around with using the Selected package for this because it also gives you the key map.

Omar: Yeah, yeah. I love the Selected package and recommend it often. I don't use it myself just because the only thing it would save me is calling embark-act, because the commands I would put in the selected key map are exactly the commands I have in the embark-region-map. For me, Selected would only save me one keystroke, which is Embark Act, so I don't feel it's worth it, but it's a great idea. For example, I do use the rectangle keymap. Yes. So they're the only difference. It's equally good an idea as Selected is. The only difference is that the rectangle keymap comes with Emacs and Selected is an external package. I decided it's not worth installing an external package when I could just use Embark Act, which I do have to use because otherwise I won't understand people's bug reports. But the rectangle mode there, that one is built in, so I just found a bunch of useful stuff in it.

Sacha: Yeah, and I noticed you have also like you have a narrow-to-point so that you can use your rectangle commands to yank something into it, so I get the sense that you use rectangles a fair bit.

Omar: You've really read my configuration very carefully. This narrow-to-point is subtle. I am very impressed that you figured out the reason for it.

Sacha: I started digging through narrow-extras because I saw your narrow-or-widen-dwim and I said, yes, I need that in my life.

Omar: I don't think... I took it from somebody. Endless Parentheses, probably. The issue with narrow-to-point, the reason you need it, is that if you insert a rectangle somewhere, try to insert it in a blank line, and it'll overlap with what was after it. But if you first narrow to the point and then insert the rectangle and then widen again, it gets its own blank lines. That's the reason I have it.

26:30 Multiple cursors

Sacha: @zor_​org asks, was there a time you wanted multiple cursors? Have you ever been tempted?

Omar: Multiple cursors. I think it gave me a false sense of security which is why I experimented not using it and then the experiment just never stopped. The thing with multiple cursors... Multiple cursors are more interactive than keyboard macros, because if you can see several cursors on the screen, you can visually make sure that what you're doing does apply correctly at each of those locations. But then I started noticing that that made me feel very confident I was doing things the right way in multiple cursors, but there were some cursors offscreen where I wasn't paying attention to what was happening there, and then I got it wrong and was more confused. Just psychologically, a keyboard macro, since I know I don't see the other places where I'm going to run it, I'm more careful when I record the keyboard macro. It's a psychological trick I'm playing on myself. By using keyboard macros instead of multiple cursors, I force myself to pay more attention to what I'm doing.

27:40 Block-undo and regular undo

Sacha: Does the block undo still let you select a region in order to undo just the part that was within it, in case you notice offscreen that it's done something bad in just these entries?

Omar: Yeah, that's completely independent. That built-in Emacs behavior is not affected by undo boundaries.

Sacha: Wait, is it?

Omar: If it overlaps with part of... I don't know. Sorry, sorry. I don't know. So if I have a big change that I amalgamated into a single undo, and then I pick a region that overlaps partially with that but not completely, what would undo and region do? I don't know. I think it... I'm just guessing. I would just think that it sees that the affected region by the big block undo is not completely contained in the region and then it doesn't undo it.

Sacha: Okay, so I'm just going to conclude that you do not make mistakes with your keyboard macros.

Omar: I can easily undo them instead of having to keep running on undo. So it's not that I don't make mistakes, but that I try to fix them right after running the keyboard macro.

Sacha: All right, all right. I had another question.

28:53 Cycling through Embark targets

Sacha: Ou've got a lot of different Embark maps and you've got a lot of different Embark targets. How do you handle going through the different ones that are at the point? At the moment, I've got the label at the top and I just flip through it. I know sometimes I need to hit it twice or sometimes I need to hit embark-act three times for this kind of thing. How do you distinguish between lots of them when you're just going through it?

Omar: I think that's the poorest part of the user experience with Embark Act currently. I don't really like it, but I don't have a good alternative. A lot of people like expand-region and I don’t like it because I feel like I have to hammer it off. I prefer to have a lot of
 This is another thing I learned from Vim: have a lot of commands to mark specific things and just memorize all of them. But expand-region says, no, don’t memorize that. Just hammer on expand-region until you get the thing you want. Ffor me, even though it's objectively fast, it just feels very slow. It feels like I have to hit it four times whenever I want to mark something. I get the same feeling from cycling in embark-act. I don't really like it. But if we had come up with a better alternative, and I say we because I discussed this in the GitHub issues with with Daniel Mendler and Prot, and I think @hmelman was also in those discussions, and maybe Clemens Radermacher? I just couldn't come up with a much better alternative, so I put up with it. I don't need to cycle that much. I almost always want to act on the first target. Which is unfair, because I decided what the first target is in the default configuration, so it's sort of tuned so that I hardly ever need to cycle. I apologize if it means other people need to cycle a lot.

Sacha: Nonsense. We can all modify our target list, so we can always tune it to what we want.

Omar: I mean, it's a lot of work, right? I think the default Embark configuration is over half of the source code of Embark. The configuration is... Where does that start? Oh, I wish the autoload cookies were not in the outline.

Sacha: If you do a space, oh, I guess it doesn't do that, right?

Omar: Oh, yeah. For orderless, I use the escapable spaces, so I can do that.

31:39 Imenu for navigation

Sacha: I should also point out that your config uses a lot of imenu also, which was another interesting thing I picked up.

Omar: Yeah, I like imenu, yeah. I should add imenu for this. One thing I did to imenu is I added a section for key maps.

Sacha: I saw that. You have a regular expression so you can see it easily.

Omar: Right. It's not half, but a big chunk of Embark is just the default configuration. It would be a lot of work to configure Embark from scratch. That's why the package comes with an extensive default configuration.

Sacha: Charlie Baker says, “I have embark-act set up to expand in the same way expand-region does, but with Embark’s type awareness, it's easy to add a contract function.” I guess maybe also some highlighting helps with that. Charlie also says, “I also have a completing read interface in the transient menu to jump directly to one of the many types under point that I'm seeking.” Charlie, you're going to share somewhere so I can steal that part of your config, right?

Omar: I mean, that would be something I would consider adding to Embark itself.

32:51 Collaboration

Sacha: You mentioned having all these conversations with Daniel and others through GitHub and other things. I wanted to touch on that because I think in the Emacs community, it's pretty rare to find people who are collaborating on packages and packages that work so well together. The partnership between your packages and Daniel Mendler or Minad's packages with Consult and Vertico and Marginalia is really nice. We don't see a lot of examples of that kind of inter-packaged conversation as much. How did that start?

Omar: I think it was mostly Daniel's initiative. I had started work on Orderless and Embark. I think his first package was Consult, maybe, of this family of packages. I remember Embark was a pretty sad shape when Daniel started raising issues on the Github. He really lit a fire under me to improve Embark. It started with him complaining about things in Embark, and I immediately realized that he was thinking very carefully about the user experience, so I thought he is full of good ideas and I should listen to them. Back then at the start of Embark and Orderless, Prot was also very involved in discussing the design. All of this is on GitHub issues. Some software archaeologists can find all of it. So I think we started working together when we realized we were both writing Marginalia, so we decided to merge those two packages into a single one. I think maybe the name Marginalia was suggested by Prot, I don't remember, but it's a very good name. The collaboration was completely unplanned. We just did it because we had already talked on the Embark issues and Daniel's suggestions improved Embark a great deal in a short amount of time. So then when we both realized we were writing something like Marginalia, we decided to just merge those two packages and write a single one. Since that worked out well, we kept on collaborating. So far, we haven't co-written any other package. One thing like that is that now Daniel is a co-maintainer of Orderless, which is great because Daniel is extremely efficient at fixing bugs. He does it instantly. He figures out what's wrong and has a patch in a few minutes after he looks at the issue. He looks at the issue the day it was posted or the day after. I can't do things that quickly. It's great that he's helping out with orderless. It wasn't planned. It just felt right from the very beginning. I immediately realized he had some great ideas and implemented a lot of them. Then we started doing that the other way around. I started commenting on a bunch of issues in Consult and Vertico. I think I exerted some pressure on Daniel to add features to Vertico, like the grid view and the horizontal view. Or maybe specifically the grid view, because at the time I was... I'm sort of slow to switch basic Emacs infrastructure. I wasn't using Vertico for a long time, even though I was like opining on the Github issues for Vertico, and the reason was that I was stuck with the vastly inferior embark-live. There was this embark-live thing where you could pop up a buffer with the targets in the minibuffer, which just means a completion candidate. So you could use Embark as a kind of completion user interface. It was very slow, but it was very featureful. You could do a vertical list. You could do a grid. In the list, you could activate zebra stripes. Yeah, you can see that's been removed from Embark. But I kept saying to Daniel, I'll switch to Vertico if you add a grid view. He eventually did add the grid view. I kept my word and switched to Vertico, which is much better than the thing in Embark. I was just being stubborn by not switching earlier. But if I had switched earlier, maybe Vertico wouldn't have a grid view.

Sacha: I think it's definitely a good example of a set of packages that has... So all this started in about 2020s or so. So we actually can see how people have gotten into using Vertico and all the other packages compared to, say, looking at more popular packages that have been around for a long time. "Of course everyone's been using Org Mode for a long time." It's there. It's part of the fabric.

38:01 Technology adoption and Emacs packages

Sacha: It's very interesting to see the technology adoption around it. A lot of the things that people struggle with as package authors is getting other people to try out their stuff. With Orderless and Embark probably in the early days, what was that like to put this thing out there in the world and have people start to try it? How did people find it?

Omar: I personally found it very scary. At the beginning, I still thought Embark was a part of my personal Emacs configuration that sort of grew out of control and I decided to publish separately. But then I have all these people telling me how to improve what I still thought of as part of my personal configuration. I think one thing that helped was that people made very good suggestions. So I realized, no, no, it's worth publishing reusable parts of your configuration just for the GitHub issues, just for people finding bugs and suggesting improvements and so on. But yeah, I had to adjust to having some users. At first, it was very few people. But then they got added to Doom. I think they were made the default in Doom. That was a huge influx of users. That was very scary. We were suddenly flooded with new bug reports, like all of the packages in the family. I remember feeling like there's a horde of Doom users running at us.

Sacha: All right. So, starter kit, then everybody gets into it, and then everybody starts talking about it because they're like, yeah, you know, it's great. You can specify things out of order. You don't have to remember what words come in, which order when you're completing things. Those of us who aren't on starter kits are like, yes, we should try that too. That's how it's done.

Omar: Doom helped a lot to raise awareness and adoption.

40:06 Personal packages and naming conventions

Sacha: You've got a lot of other small packages. For something as small as block-undo, which you showed us, it really just fits in one screen. Is that something that you would set up as a different repository or just as a file within your current one?

Omar: No, those are all in my user-lisp directory.

Sacha: I have actually successfully used use package to grab stuff out of your user-lisp directory and use them in my config. Yeah, it works. I just say, all right, my load path is here where I've checked out your source code. It defines these commands. Then I can bind your functions to my shortcuts. Although, because your functions are named the way that I would expect Emacs functions to be named, I've been defaliasing them so that I don't accidentally say, oh yeah, that's totally built in when it isn't.

Omar: Yeah, I'm inconsistent with these little packages in my user-lisp directory. In some of them, I do stick to the convention that the package name is a prefix for all the functions, and for some, I don't. For some, I just try to name them the way exactly what you said. Like, what would these be called if they were built into Emacs? Which means they don't share a consistent prefix often. I should probably make that more consistently use the package name as a prefix so that they're easier to dot.

Sacha: Or I have another suggestion. You could get apply-kmacro-to-paragraph or whatever that is into core Emacs. That would be great for everyone.

Omar: Yeah, maybe that one is useful enough. Some of these I don't use anymore because I think I've substituted them with workflows with Embark. For example, eval-region-advice. It bothered me that none of the evaluate commands are “do what you mean” in the most common sense in Emacs. The most common sense of do what I mean in Emacs is if the region is active, use the region. Otherwise, do the normal thing. All of the evaluate commands should evaluate the region if the region is active. So that's what this does. But I don't use that anymore, because to evaluate a region, I usually use embark-act e. What else is here?

42:26 find-file-at-point and directory names

image from video 00:43:06.133Omar: Oh, some of these things are like tiny things that are almost invisible, like this. In Eshell buffers, By default, find-file-at-point doesn’t realize that if it sees the filename printed in an eshell buffer, it won't look at the prompt to figure out what directory it came from. If you type ls and you're in your current working directory, all of those listed files, the find-file-at-point guesses that they are files in the default directory, and that guess is correct. But if, further above, you had gone into a different directory, called ls there, then those files are no longer in what is now the default directory. So this just adds a little bit of smarts to find-file-at-point. It looks at the prior prompt to see what directory that was run in, and then tries to see if the files it sees there are in that directory. Of course, the only reason I want this is because I sometimes use embark-act on files I see written in the Eshell buffer.

Sacha: I love this. I love how all these little bits of code show that at some point you were annoyed by a tiny, tiny problem and you're like, that's it, I'm just going to write some code and it's never going to be a problem again.

43:49 The value of using Emacs’s APIs

Omar: One thing I like about this is it also shows sticking to Emacs APIs. Embark uses find-file-at-point to guess what things are referred to files. I did this to improve the functionality of Embark in Eshell buffers, but what it really does is improve the functionality of find-file-at-point, which I hardly ever use directly. I almost always use it through Embark.

Sacha: Send it upstream! Okay, so you use Emacs for working with a shell, working with your files, doing math, doing some programming as well. Are there unexpected things that you use Emacs for?

Omar: I don't think so. Mostly I write. It's mostly writing prose. I think I was slightly misled about what a job in academia is like. I mostly write emails. That's the bulk of my job by the time consumed.

44:56 org-ql and usual files

image from video 00:45:18.667Sacha: You have some shortcuts around org-ql for managing your agenda or other things.

Omar: This notion of the usual files. I was often using org-ql to search this set of files: every file mentioned in a refile target, every file mentioned in a capture template, and every file agenda file. Here it is. So I thought that's what I want to search. I want to search every file I mentioned in a refile target, every agenda file, and every file that I mentioned in some template. That's what this does.

Sacha: I don't know if you trust your hiding things enough for us to try that. Since you put so much work into it... Or do you want me to hide the screen first and then you can let me know when it's safe to look?

Omar: No, no, that's fine. I can show you the censorship process. What I thought I would do is I could show you the... Wait, what is this? Why is that not an action? Oh, library. Oh, I have not loaded this. Yes, now it's loaded. Oh, so this should be... Why is this not recognizing org-ql usual files as a variable now that this is loaded?

Sacha: Oh, great. I'm also open to debugging demonstrations live because that is something that a lot of people do.

Omar: Sorry, I think it just hadn't loaded this file. Now I ran a command from here and now I should have a variable. Yes, I have a variable. So we can go to Customize.

image from video 00:46:33.967Omar: The ones that have sensitive information are tasks, home, health, Definitely work. Journal. I don't really mind people seeing my journal, but that's boring. There we go. Yeah. So now I got rid of all of the sensitive files. And so now I can show you. I usually just search through all of these files at once. So I had a list of things I wanted to tell you about.

47:06 Shortcuts for org-ql search syntax

Sacha: I should also point out that your config has some stuff for inserting things into the org-ql search syntax.

Omar: You're extremely prepared for this chat. Yes, C-,has a little key map that will insert stuff like priority. Oh, I don't have, let me remove “Sacha”. Oh, yes, everything that I have with priorities is in one of the files I removed. I only use priorities for work.

Sacha: Okay, gotcha.

Omar: We could use to-dos.

47:43 Org TODO states: TODO, WAIT, DONE, NOPE

image from video 00:47:45.733Sacha: I love that you have a to-do state called NOPE.

Omar: It's for things that are cancelled, but I don't want to delete them yet. Actually, it's mainly there because when I archive them, I want to know that I had that task at some point, but decided not to do it.

Sacha: Well, it's so much less verbose than CANCELLED, so I think I might actually just...

Omar: For a long time, I was using monospace fonts, so I wanted to have everything fit in four letters. So I have... Yeah, all of my, I have TODO, WAIT, DONE, NOPE, and they're all four letters long.

Sacha: Nope. Gotcha. Okay. So that's org-ql and that's your inserting thingy.

48:26 The inserter macro

image from video 00:48:36.667Sacha: The other thing that I wanted to point out that your definition of the inserter was nice because it's a macro. So you have this thing that allows you to just define all these interactive functions. You can add it to the key map because the key map expects interactive functions. If people are watching, yeah, this is something you can do.

Omar: I should tell you that there was actually a serious performance bug previously. What I had before this
 This string is a keyboard macro that inserts those letters. It is extremely slow if you do it that way for some reason. I think org-ql searches after the T, after the O, after the D, after the O, after the colon. For some reason, that was extremely slow. So I switched to these lambdas that just call insert. That does it in a single step, and it's instantaneous. But my first instinct was, oh, well, this is a good use of keyboard macros. I'll just assign these to keyboard macros. It's not a good idea in this particular case.

Sacha: I imagine there should be some kind of debouncing on org-ql to make it not do that if you're typing very quickly, but... I don't think there is.

Omar: Let me see if... Maybe also do a longer one so it...

Sacha: That's okay. I take your word for the bug that you ran into.

Omar: I wanted to show you just because it just feels like a really long pause, but it didn't work right now and I don't know why not. That's okay.

Sacha: Curse of the live demo. So that's inserter.

50:05 luggage: generative art experiments

image from video 00:51:32.367Sacha: One thing that I definitely want to make sure we had time for was your little generative art experiment, luggage, because you're having fun with Emacs.

Omar: Yes. Yeah. There are some people doing amazing generative... Oh my gosh. I do not even have it installed. Yeah. Let's... I forgot that we were going to do that. That's okay. But it should be easy. How is :vc used?

Sacha: (:vc (:url 
)).

Omar: I have to go to a previous example to figure out.

Sacha: I'm surprised you don't have a consult-line and then just embark-insert.

Omar: I do that. I do that a lot. But I forgot this time.

Sacha: Actually, looking at your config, I learned about consult-multi-occur because apparently there all these multi-buffer equivalents to the commands that I've been using. That is really useful for using stuff from buffers I'm not even looking at.

Omar: Okay, load it.

Sacha: Let's see if it actually can still do the thing. There we go. So you have some Emacs Lisp to generate this SVG. Yeah, and it's just got...

Omar: And which other ones do I have? Luggage. There we go. Tubes. I think this one has some nice other color schemes. Classic? Classic is the one. Oh yeah, stained glasses is the one I wanted.

Sacha: Nice. I wanted to mention it specifically because a lot of times people think, oh, Emacs is a text editor. But because it's also got support for SVG and other types of graphics, you can play around with it. Sometimes it's just doing it for fun like this, but also there might be some other visualizations that you can do with Emacs. That is actually pretty interesting.

Omar: Yeah.

image from video 00:52:26.800Omar: Have you heard of this program?

Sacha: No, I haven't come across it.

Omar: There's an entire book with this title. So it's a single line of BASIC. 10 print. Oh, I'm not, I don't know BASIC, but the idea is like you randomly pick either forward slash or backslash.

Sacha: Oh, yeah, yeah, that makes sense now.

Omar: I'm sure this is not correct BASIC, but, you know, something like that. Yeah, I get the idea. Yeah. And that's what this does. And then you GOTO 10. It's like... It makes these elaborate mazes. It's an extremely simple program.

Sacha: So this is the kind of stuff you do for fun. I mean, you probably do lots of other things for fun, too.

Omar: Yeah. But this... No, that's not the buffer I wanted. Where is... Did I kill it? I killed it. Yeah, one of these I did. What is it? Dominoes. Yeah, this I did for a math talk I gave. It just produces random domino tilings of the board. I gave that talk from an Org file using Prot’s Logos package. I usually use PDF slides, but that time I wanted to use an Org mode buffer because I was going to run code on the computer. Like this, for example, generating random domino tilings.

53:49 Teaching and Emacs

Sacha: So you've given a number of talks. Do you also teach any courses?

Omar: Yeah, I do teach both undergraduate and graduate math courses. Recently, mostly graduate math courses. But yeah, I really like teaching. You always learn something. Even the subjects that you think you know very well, teaching a course always teaches you something new.

Sacha: Have you gotten students into Emacs?

Omar: No, I don't even try. “I use this weird text editor Emacs, it's pretty cool, but it takes a while to learn. I'm not recommending it. I love it. If you do try to use it, you can ask me anything.”

Sacha: Yeah, it's pretty hard. I know some professors are like, okay, this is what we're going to use for the course. But I imagine, depending on your subject matter, you might already have your hands full teaching the subject matter rather than adding it.

Omar: Oh, yeah, yeah, definitely. No, no. The students I try to talk to Emacs about are like the students that are writing their thesis with me. No, never in a course. I never mention it.

54:53 The print10 generator

image from video 00:54:56.900Omar: Oh, there it is. In the docstring, I have the correct program in BASIC. The backslash and the forward slash are consecutive ASCII characters. 206 and 207. You add a random number between 0 and 1 to this one and then round to the nearest integer.

Sacha: All right. You can get surprisingly interesting patterns out of it. That is also very cool. Fun with Emacs. This could definitely be like a zone screensaver if you wanted to.

Omar: Yeah. I just thought it was really nice that Emacs displays SVGs natively. Those are very easy to generate by text.

Sacha: Are there other interesting corners of your config that might not be immediately obvious to people who are just reading the source code? What other workflow things are nice for you?

Omar: Sorry, what were you saying?

Sacha: I can also start just occurring through my config for all the things that I've stolen from your config in the last two days.

Omar: I don't think I have any concrete idea of what to show now. I think we've covered most of the ones I wanted.

56:23 arXiv

image from video 00:57:42.967Omar: As an academic, I deal a lot with preprints on the arXiv, so I have a little library that will show me the PDF or copy the URL. I like personalized software because it does exactly what you needed to do. I noticed that there were a bunch of tags on Mastodon that related to archive papers. Often when I was in a Mastodon buffer, I wanted to do something to the paper mentioned at point. That's one of the acceptable inputs for my arXiv library. So, for example, this is an arXiv link and I can ask it to show me. So that's a bug. This should definitely have visual-line-mode activated. I can just quickly read the abstract without visiting the archive website.

image from video 00:57:51.200Omar: Or I can open the PDF.

Sacha: Very cool. Very convenient.

Omar: Yeah, so. I like that in Emacs you can do all these personal things that you'll need but are not likely to be needed by many people. They're just easy to do. Vim is also very configurable, but the Vim script language is sort of awkward, so I never did anywhere close to the amount of configuration in Vim that I do in Emacs. That's why I would never go back to Vim now. I would miss all the stuff I've written.

58:29 Toggle keymap

image from video 00:59:06.133Sacha: One of the little personal customizations that I liked reading in your config was the fact that you have a key map just for toggling various things like the mode line or the header, you know? Yeah. You want to tell us more about your awesome key map for that?

Omar: You don't need them that often, so it's OK if it's under a long prefix. It's just tedious when you want one of them, to have to type the command name. It also helps me remember which things I commonly toggle. I often have to hit C-h here and see what I have available to toggle. I don't know why toggle is a category for commands, because obviously these are very disparate commands that do very different things. But they're things that you occasionally turn on or off, and it's convenient to have them all together. Choosing the letters here was very difficult. Everybody wanted to have the same letters. L was for visual lines. P for variable pitch mode because I think of them as proportional fonts. It took a lot of tweaking. I'm sure if I looked through the GitHub history, you'd see a lot of tiny changes just changing the binding of one of these.

Sacha: I find it difficult to get the hang of new key bindings, especially for things that I'm not using often enough for the key bindings to stick.

Omar: I often forget that I have a key binding for something.

Sacha: So how do you deal with that? I mean, yes, you stick it in an Embark keymap and you just bring it up to the target.

Omar: Yeah, I do use Embark bindings in keymap a lot to just explore keymaps and remind myself. I don't need to memorize a binding. I just need to remember that I have a binding. If I have a binding, I can find it later. But sometimes I don't remember that I have a binding, so when I'm looking at my configuration, I'll just re-scan what things I have bound from time to time. Mostly I stick with just
 I know under what the start of the prefix is, and then I'll just use Embark to remind me of what I have there. Which is nice, because you can also see the docstrings.

1:00:54 isearch-delete-wrong

image from video 01:01:32.267Sacha: I like how you try to use some of the conventions to make it somewhat easier to remember. One of the key bindings that you have that I want to point out, because I think it's a useful technique, is you have an isearch-delete-wrong.

Omar: Right. isearch keeps track of where the last portion of the search string that matched is. You can see it highlighted in the buffer, right? So this means it found up to “del”, and then it didn't find "tok". isearch-delete-wrong will just delete that entire part.

Sacha: So that way, you can just restart from what actually exists. Combining that with the fact that you've got your search whitespace regular expression to be a wildcard means you can...

Omar: Oh yes, this I stole from Prot. He recommends this.

Sacha: Yeah, which means you can use isearch to find things, even if there's other stuff in between them. When you can't find something, you can restart.

Omar: I'm not sure... I'm not sure if this is the best setting. I want to be able to search this way sometimes, and sometimes with whitespaces treated literally, so I should keep statistics on how often I actually have to turn this off. It might be that for me the better default is the other way around. You can turn it off with M-s SPC. Match spaces literally. isearch-toggle-lax-whitespace. I don't know. Maybe for me the default would be to treat whitespace literally, because I find that if I have a space in my search string, I often want to turn on the literal matching. But it's probably still this is the better default. I think I do it less than half of the time I have a space. But it's not that far from half, it feels. I don't have statistics.

Sacha: How do you even collect statistics on this? Aside from making a little note every time you're like, oh, I didn't like this.

Omar: I mean, I would instrument isearch somehow, but I haven't thought about that problem.

1:03:14 isearch - continue from the beginning of the match

image from video 01:03:44.400Omar: One nice thing I do with isearch is another one of those things I got from Vim. isearch, by default, leaves you at the end of the match. I almost always want to be at the beginning of the match, because that's what I got used to in Vim. I think it must be here. I have something exit at start. I tell isearch to exit at the beginning of the match. The way you use this is you install it as a hook, I believe. Is that right?

Sacha: You seem to have options.

Omar: Yes.

Sacha: I see. So S-RET lets you exit at the end, and then by default... Yeah, which is Emacs default.

Omar: But I find that the better default is to exit at the beginning. Yes, and that's the whole point of that. For example, if I want to mark until that parentheses, then I would search for the parentheses, and I don't want to include the parentheses. That's not a good example. But with a word, it's often like, I'm looking for a word, but I want to highlight up to the end of the word. It's just like, if you want to mark a region from point to some search term, with the Emacs default, what you have to search for is the thing that is at the end of the part you want to match. But often I want to say until like the thing that starts here. It's just my brain works that way. So for me, it's much better to exit at the start of the search. Which means I don't understand isearch on other people's Emacs. It just leaves the point in the wrong location all the time. If you're going quickly, you won't realize that it's just a mess. It does mean that I can only use isearch if it's configured this way.

Sacha: Well, that's the thing about Emacs, right? Once you've got it set up, you've got to use your config because everything else just feels off. It just feels weird.

Omar: Yeah, that's right.

Sacha: All right.

1:05:12 Using keymaps to remember sets of commands

Sacha: Going back to the toggle keymap, @gcentauri says, I'm not lazy enough. I just M-x orderless consult, find the thing that I'm toggling, which I do a lot also. I just use M-x for all the things because I can just specify parts of it.

Omar: There's some toggles I don't have in the keymap because I use them very rarely, but yeah. What I like also about the keymap is that it's a place to remind myself of the toggle commands. I often just do this. What was the thing? I haven't used that in a while.

Sacha: Having a shorter list, it means you can just use recognition instead of recall, right?

Omar: It's short enough that I can read through it.

Sacha: I like that a lot. I like the fact that with that Embark C-h screen, you can use completion even to select the commands from that subset.

1:06:04 Other things from the config

Sacha: A couple of other things that I picked up from your config: There’s your dired-open-externally, so it makes it very easy to open something in an external application.

Omar: And it just calls Embark open externally. This function moved back and forth from different places. I think embark-open-externally used to be in consult. Daniel said he felt it didn't fit in with consult. Embark consult would put it in keymaps. He was right. Consult didn't have a very clear personality at the beginning. It was sort of like a grab bag of commands. Eventually, what gelled is that a command should be in Consult if there is a useful way to write previews for it. So, preview is the distinguishing feature of what is a good fit for Consult. Now, I hope Daniel would agree with that. That seems to be the criteria now. That's great. I absolutely love preview. That's one thing I miss a little bit with org-ql. I use org-ql mostly to search through Org files, but the preview is kind of manual in that I use Embark to do it. If I want to preview a command, I just use Embark to do what I mean.

Sacha: Yeah, that's a good idea. I should try that.

Omar: So any command that doesn't have a preview, I mean does, you can just use embark-dwim, it'll complete the command for you.

Sacha: Okay, the kid has arrived, so I have to go off to lunch. But thank you so much for the quick peek into your config. I'll put the transcript together and then people can do that. But in the meantime, people can look at your config for all sorts of wonderful goodness.

Omar: Thanks.

Sacha: Thanks to everyone for hanging out. Looks like the isearch tip was popular, so you might see a lot of people getting that from your config. Anyway, thank you so much for this. I’ll see you around.

Omar: Thanks, Sacha. This was fantastic.

Sacha: Alright, nice.

Chat

  • takoverflow: ​​Hello Sacha and Omar, thanks for this chat! :)
  • CharlieBaker707: ​​Definitely going to add the keycast transparency to my config! I've been wanting that for a while!
  • gcentauri: ​​i'm still a minibuffer noob - its been nil my whole Emacs life!
  • CharlieBaker707: ​recursive minibuffers is amazing. biggest win for me is that it lets you select things and paste them in, like from a completing-read's history for example
  • gcentauri: ​haha apparently i do have recursive minibuffers set to t, along with my Vertico config đŸ€”
  • Zor_org: ​​was there a time you wanted multiple cursors?
  • Zor_org: ​if so, was there any workaround you thought of with embark or kmacro?
  • gcentauri: ​keyboard macros are a fun mini-game
  • CharlieBaker707: ​I have embark-act set up to expand in the same way expand-region does, but with embark's type awareness. It's also easy to add a contract function.
  • CharlieBaker707: ​I also have a completing-read interface and a transient menu to jump directly to one of many types under point that I'm seeiking.
  • CharlieBaker707: ​For sure!
  • CharlieBaker707: ​I was going to create a tiny extension, but I can open a PR in embark!
  • Zor_org: ​even more crazy with elfeed 4.0
  • gcentauri: ​I found Orderless and Embark through Daniel's suggestions in his packages :)
  • Zor_org: ​if emacs gets canvas patch soon, more things can be done in luggage (lik gifs and image frame as well)
  • gcentauri: ​i am not lazy enough, i just M-x orderless consult find the thing i'm toggling
  • PuercoPop: ​​I didn't knew isearch had a built-in way to fix the isearch quirk. Now I can remove the snippet I use the implement it that I cribbed from the internets
  • gcentauri: ​yeah adding something to a keymap you make does help recall
  • PuercoPop: ​​The isearch quirk is a common complaint from what I understand
  • gcentauri: ​yeah i'm gonna use that iserach bit
View Org source for this post

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

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

Sacha Chua: Yay Emacs 32: Sacha and Prot Talk Emacs: May I recommend...

In this livestream, I chatted with Prot about the May 2026 Emacs Carnival theme "May I recommend". It was a joint braindump of quick recommendations for people at different points in their Emacs journey, building on our conversation about newbies/starter kits and the newcomer experience all the way up to power users, Emacs Lisp coders, and package developers.

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

Related links

You can add the iCal for upcoming Yay Emacs episodes to your calendar. https://sachachua.com/topic/live/upcoming-livestreams.ics

Find more Yay Emacs posts or join the fun: https://sachachua.com/topic/live

Chapters

  • 0:00 Opening
  • 2:27 Tip: Less is more. Start small.
  • 4:07 Tip: Start with what is built in
  • 4:27 Skill: Figuring out the words to look for
  • 6:25 Tip: Be okay with starting over
  • 8:26 Skill: Learning to discover
  • 8:42 Tip: Read manuals for fun
  • 10:16 Tip: Use Emacs bookmarks to save your place in the manual
  • 10:43 Tip: Generally, investing time into navigation and note-taking workflows pays off
  • 12:19 Skill: Keyboard macros
  • 12:53 Skill: Modifying the behavior of code via hooks and advice
  • 13:15 Tip: Learn to think in terms of buffers and windows
  • 14:07 Skill: Reading the source code; Tip: Just jump in
  • 15:33 Tip: edebug is great for exploring code
  • 16:26 Tip: Reading tests can help you understand code, too.
  • 17:02 Skill: Idiomatic Elisp
  • 17:17 Tip: Write tests.
  • 17:52 Tip: When writing Emacs Lisp that expects a list, use plurals
  • 18:59 Tip: When naming, be verbose rather than terse
  • 19:46 Tip: Iterate on your workflow in small steps
  • 20:20 Tip: Make things more automatic, and use context-sensitive clues
  • 24:48 Skill: Thinking in terms of elements
  • 26:16 Skill: Reading other people's configuration and adapting ideas to yours
  • 27:07 Tip: Start with focusing on just one thing
  • 27:33 Blog posts and videos are useful
  • 28:09 Tip: Take notes as you learn, and ideally, share them too.
  • 28:54 Tip: Accept being a beginner.
  • 31:16 Group: Power users
  • 32:13 Tip: Browse through package lists
  • 32:25 Tip: Dive deeply into the packages you have: customization options, code, etc.
  • 32:41 Tip: find-library gets you to the source code, occur can help you browse it
  • 33:29 Tip: You can also browse through Customize
  • 33:48 Tip: Have fun with randomness and serendipity
  • 34:32 Tip: Check out people's workflow descriptions and stories
  • 35:42 Resources: manuals, Mastering Emacs, Emacs Lisp Elements
  • 37:29 Skill: Figuring out what's possible and making a habit of writing tiny functions
  • 37:45 Skill: Being mindful of what you do over and over again
  • 38:26 Tip: Keyboard macros can help you jumpstart custom functions
  • 39:11 Tip: Use C-h k (describe-key) to describe shortcuts or menu items
  • 40:04 Tip: You can set up M-x to show keyboard shortcuts too (Marginalia?)
  • 41:26 Resource: Emacs from Scratch series by System Crafters
  • 41:50 Tip: Old tutorials can still be useful, although don't treat them as the sole source of truth (things may have changed since then)
  • 42:55 Skill: Finding preferred resources
  • 44:12 Tip: If you find your tribe, look for ways to keep in touch with them
  • 45:00 Tip: Manage unequal RSS frequencies with folders or tags
  • 46:33 Tip: Doing more things in Emacs has compounding benefits
  • 48:31 Tip: Learn to think of it as just text
  • 49:46 Tip: Take notes along the way
  • 50:16 Tip: Explore different ways to navigate and act on things
  • 51:09 Tip: Learn to combine different building blocks
  • 52:47 Tip: Get the hang of keybinding conventions
  • 56:06 Tip: Use which-key for keybinding help
  • 57:41 Tip: Figure out your ergonomics

Transcript

Expand this to read the transcript

0:00 Opening

image from video 00:00:38.400Sacha: My typing is still going to be very loud, but that's okay.

Prot: That's part of the charm.

Sacha: Okay. All right. Here we go. Let's go live. Hello, everyone. This is Yay Emacs [32]. I forgot which number. Anyhow, I'm here with Prot because it's Emacs Carnival for May 2026, and the theme is "May I Recommend" because I like puns and couldn't pass up the chance to say "May." So "May I recommend..." is our topic, and our goal for this one is to brain dump a whole bunch of things that people might find useful in their Emacs learning journey. We've already talked about newbies and starter kits in the previous two conversations we've had in Sacha and Prot Talk Emacs. This time, we're going to focus more on *users* who are getting started with... They've decided this is going to be their everyday tool. They want to learn more about keyboard shortcuts and finding their way around, building the habits, finding their preferred resources. *Power users*, maybe, who are starting to look at different packages, these are maybe the people who are saying, okay, maybe let's try this package for working with Org Mode in addition to the basic stuff, or let's try doing email in Emacs. *Customizers*, who are beginning to get into Emacs Lisp to write functions. This is where you start to customize it a lot more to your tastes and your workflows. *Contributors*, people who are sharing their source code, maybe even turning it into packages, participating mailing lists and discussions. So this whole range of people all working on different skills at different levels. What I think we're going to do with this is we're just going to braindump a whole bunch of recommendations. You're welcome to ask questions, and I'll ask you questions as well. We'll just untangle everything and organize everything afterwards.

Prot: That's great.

Sacha: There we go. In this list of skills that people can develop, are you thinking of other skills that aren't on this list yet that do make a big difference to how people use and learn Emacs?

Prot: I need to enlarge my screen a little bit. I think what you have there is good.

2:27 Tip: Less is more. Start small.

Prot: What I had in mind also is more of a meta-point, or more general thing, like an approach style, which is "less is more," if I were to condense it. Start small. Make sure you make it work when it's small. Extend it from there. Don't start big and try to simplify it, because that doesn't work.

Sacha: I grouped that idea under managing time, notes, and attention and also breaking things down, because the overwhelming nature of things is something a lot of people struggle with, both Emacs and elsewhere. Even just that meta-skill of saying, "Okay, this is a small chunk that I'm going to focus on because I know that's what my brain can handle" versus "let's architect this entire thing" and you're six hours down the line and you're nowhere near the thing that you want it to do.

Prot: And of course Emacs invites you for that because it's like, here are like a hundred powerful tools for you to combine in ways that nobody else has thought of before, right? So it's like asking you to do that, but it's a trap. You don't want to go down that route. Or at least don't go there too early.

Sacha: Managing the rabbit hole. Yes, there are going to be a lot of temptations and some of those temptations are quite legitimate. Yeah, you do have to figure this part out in order to get this other thing that you wanted working. But sometimes it's just a trap.

Prot: Yeah.

Sacha: So that's managing. What other meta-skills here should we talk about as a framework so that when we dive into the specifics, we know we're covering a lot of the ground people need?

4:07 Tip: Start with what is built in

Prot: Not so much a meta skill, but consistent with this line of reasoning is as a good heuristic, start with what is built in and extend from there, because usually what is built in will give you a baseline of functionality. It works with a "less is more" approach.

4:27 Skill: Figuring out the words to look for

Sacha: I feel that sometimes figuring out the words to look for, finding out what it might be called in Emacs source or in the built-in packages... That's something that's hard to develop unless you're reading manuals and reading other people's posts because the terminology can be quite arcane.

Prot: Oh yeah, for sure.

Sacha: Getting a sense of what might be built in and what it might be called and where to look for it, I think, is definitely a skill.

Prot: One good way to think of this is, what do I want to do? In the most simple form, if you forget about Emacs for a second, and you're like, what am I trying to do? I'm trying to write a blog, or I'm trying to deal with email correspondence, or I'm trying to manage my TODOs. In its most simplest form, how can I solve this problem? That can already help you formulate the questions.

Sacha: Formulating the questions is actually really hard. Sometimes people don't even notice that there's a question that they can ask, and they don't know what kinds of solutions might address that problem actually. They get distracted by A, but actually it's B that will solve the problem. Considering the different kinds of solutions that can address the same problem, developing a sense of which ways are easier to do the Emacs way versus harder to do. Why make something really complicated when a built-in package or whatever can solve that problem in a more elegant way? All of these things require the development of intuition.

Prot: Yes, yes, and with some experience, of course, that helps, for sure. But then it's the other, which you can also consider as a meta skill.

6:25 Tip: Be okay with starting over

Prot: I believe there was also a point of this, be okay with declaring bankruptcy in Emacs. Bankruptcy, I think... the essence of that is not really much bankruptcy, but be okay with trying something, which is an experiment, and then learning something from it, distilling the essence of that, and then trying something else. I think a sense of experimentation will help you build that skill of, okay, now I can intuitively figure out what works and what doesn't work.

Sacha: I think that's a really interesting point because sometimes you get very attached to "there's this thing that I've started to build" and then you start bolting more and more things onto it, when really, sometimes the prototype is your way of understanding the problem. Then you take it all out and you say, okay, now that I understand a little bit more, what can I make? How do I change my workflow with that new understanding? Sometimes it's as extensive as declaring Emacs bankruptcy and starting again from scratch. Sometimes it's just maybe "The approach that I'm taking is not a fruitful one. I should go try something else."

Prot: Yeah, exactly. You can only have that feedback loop if you try, so trial and error is the way to go.

Sacha: @gcentauri has a question or a comment about discoverability, figuring out how to navigate Emacs in order to discover things. Where would we put that in this skill? This is figuring out the words as well, right? Isn't it?

Prot: Yeah, by the way, I'm in the chat here.

Sacha: Where did you read that?

Prot: I see it here. It was off my screen. I see it now. And of course Christian... I'm reading the temperatures in Western Europe. They are terrible. Yes, I know.

Sacha: Yeah, big heat wave.

8:26 Skill: Learning to discover

Sacha: So, figuring out discoverability, learning how to navigate Emacs. Emacs is lovely. It's self-documented, everything at your fingertips, but you've got to know how to get those fingers on them.

8:42 Tip: Read manuals for fun

Prot: The manual helps. It will present some of that. But of course, you have to read the manual. So you are in a situation where you have to have the skill of reading the manuals in order to discover, but to discover... So yeah, it's a tricky thing. You have to know where the manuals are.

Sacha: Yeah, and you have to be unintimidated by them, I think. I got into it easy because I've always been used to reading books above my level. Even as a kid, I was reading my sister's data structures and algorithms books. I didn't understand anything the first time around. But after nine times through, you start to understand some of the concepts and how they go together. The more you read something, the more of those concepts start to make sense to you. You read it, you read other things around it or related to it, and then the jargon becomes less impenetrable. You begin to understand it. So one of my recommendations is I recommend reading the Emacs manual, the Org manual, all these book-shaped things for fun. Even if you don't think you're going to immediately use 90% of the things, every time you read it, you're going to learn something.

Prot: Yeah. Plus, of course, you will know you are an Emacs user if you are reading manuals for fun.

Sacha: How else are you going to find out about Org spreadsheets and whatnot, right? It's just too big to fit in your brain.

Prot: Correct. Yeah, that's really good. You could even make it a habit of, okay, this day I will read one chapter from the manual.

10:16 Tip: Use Emacs bookmarks to save your place in the manual

Prot: Actually, to say something on this, if you learn about the bookmark mechanism of Emacs, you can bookmark info manuals. So if you are reading the manual from inside of Emacs, you can use the bookmark facility to be like, last point in the Emacs manual. You could have a bookmark that is a rolling bookmark, right? So you could be updating it whenever you go to the next chapter. This way, little by little, you can read the manual.

10:43 Tip: Generally, investing time into navigation and note-taking workflows pays off

Sacha: In general, figuring out your navigation and note-taking workflows so that they're super convenient for you, whether that's Denote or Org Mode Capture or whatever else that you're using... As you read, taking notes on the things that you find interesting in a way that makes it easy to jump back to more information is definitely worth the upfront investment of learning.

Prot: Yeah, 100%.

Sacha: @gcentauri confirms they are actually a true blue Emacs geek. "Was reading the manual right before bed and came across the forms library. No idea it existed." Read stuff, make it easier for you to jump back to the place that you left off or the parts that you found interesting. That's a great recommendation.

Prot: Just to add another metaskill related to this. Don't read it before going to bed because if you discover something useful, you are not going to sleep.

Sacha: I think the idea there is get really good at telling your brain, yes, that's really cool, but if you stay up until 1, you are going to regret it. So just add a TODO and let it go.

Prot: Exactly.

Sacha: This may have happened to me a number of times.

Prot: Yeah, yeah, same. So, only read the manual in the morning or when you wake up.

Sacha: Are there other metaskills that are not yet captured in this or do we start digging into each of these skills?

Prot: I say we dig in and if we think of something we can always add it later.

Sacha: All right. What strikes your attention here? Which of these things?

Prot: No, no. You can go wherever. I don't mind. Anything will do well.

12:19 Skill: Keyboard macros

Sacha: There's a whole lot of stuff here in the customizer, packager thing around modifying or gluing together code that is not something easy for people to pick up because they're just not used to it in other programming languages or platforms or whatever. Things like: you could use keyboard macros to cobble together a quick workflow. You don't even have to write a big function. Just developing the intuition that, oh, this is a set of repeatable functions or repeatable commands is one thing,

12:53 Skill: Modifying the behavior of code via hooks and advice

Sacha: all the way to "this is how I use hooks and advice to either modify the behavior of something where the person who coded it has anticipated that a hook will be needed here, or advice in case they didn't plan for it at all." You're just going to override things yourself. How do people develop this sense of what's possible and how to do things?

13:15 Tip: Learn to think in terms of buffers and windows

Prot: Yeah, it's a difficult skill but it's something you develop by experience. The point to remember is that in Emacs, at its core, you have buffers and everything is a buffer and buffers are displayed in windows If you think in terms of that abstraction, something like a keyboard macro becomes a tool that will jump between buffers, will switch windows. It has no problem doing any of that. You are not limited in your thought to, okay, I have to work exactly where I am right now. I think that's a general approach that goes very far with what you do. Of course, when you are thinking of the advice and the hook, that I think is a little bit more advanced because you need to also have the skills to write advice. With hooks, maybe not. But for advice, you will need to understand exactly what is happening.

14:07 Skill: Reading the source code; Tip: Just jump in

Sacha: I have definitely jumped ahead here because this also requires the skill of reading people's code in order to find out there is a hook or there is some advice that you can do, or there's a variable and this is how you can let bind it to temporarily change its value during this part of the code. Let's talk about reading source. What sorts of things help people develop that skill of reading the source code?

Prot: You have to just jump in at some point. Like, you might do it by accident when you are in a help buffer and either you misclick S, which goes to the source, or you follow the link from above. But anyway, the point is it's a good skill to just, a good habit rather, just jump in and try to read it even if you don't know any programming. Try to read it as if it's English and try to see what you can understand. And of course, some functions will be extremely difficult. Others will be more straightforward. So I think eventually by exposure through osmosis, as it were, you will already learn something.

Sacha: I love the fact that our functions in variable names are often very long and it makes sense in English because we're not trying to squeeze into some very concise, very terse convention. Just put a full sentence in there. It's fine. We just use completion anyway. It's all good.

15:33 Tip: edebug is great for exploring code

Sacha: One of the tips that I'll put in here because people sometimes miss it is the power of Edebug. If people haven't come across Edebug yet, it's great because you can interactively step through what the code is actually doing and you can evaluate what the value is of this variable at this point. And every so often I had to go into the Edebug menu bar and remind myself, okay, you can set conditional breakpoints and all these other things that I have to remember that exist and can be used. But Edebug, if you're going to learn Emacs Lisp, learn Edebug.

Prot: Edebug is really powerful for sure and it's especially useful when you have functions that are relatively long. I mean what they are doing like they have a lot of steps and you have to understand the flow. Like if it's a very short function maybe you don't benefit all that much from eDebug but in practice you will need it. It's very powerful.

16:26 Tip: Reading tests can help you understand code, too.

Sacha: And the other thing I want to point out is that sometimes packages have tests and reading the tests can give you even more of an idea of how this function is supposed to behave. It's not always the case, but when there are tests, they're great.

Prot: In an ideal world, we will update our tests.

Sacha: Alright, so that's reading source code. There's so much that's really interesting to read. Sometimes you come across interesting idioms for Emacs Lisp and you're like, oh yeah, that's a great way to iterate through all the buffers and match a certain thing, whatever.

17:02 Skill: Idiomatic Elisp

Sacha: And so if you're in this customizer phase of things and you want to move to the contributor level, learning idiomatic Elisp is definitely like, okay, it makes things a lot easier.

17:17 Tip: Write tests.

Sacha: Charlie says, "Edebug and ERT tests change the way I develop Elisp. No longer flying blind." Yeah, great. In particular, I tend to break things whenever I make changes, so it's really nice to be able to say, okay, I'm going to nail down this behavior, at least for now. With a little bit of thinking, sometimes you can write tests for things that you would do interactively. So you can test a whole lot more because you have buffers and windows than you might in other languages.

Prot: Yeah, correct, correct. And you get to see it live.

17:52 Tip: When writing Emacs Lisp that expects a list, use plurals

Prot: Just to say on this point of when you are going through the tests and through everything, one basic thing which is in idiomatic Emacs Lisp is when you are writing the parameters of a function, if you are expecting a list, you use plural. For example, you have a function that goes through buffers. Your parameter is just called buffers. That alone should tell you that it's a list of stuff. You don't say "list of buffers," right? That's superfluous. You just say buffers. This automatically means it's a list. So that's very common. You will see this a lot.

Sacha: Here I am, I've been calling my variables buffer-list. Sometimes figuring out what I should call a function or call an argument is a bit challenging, but I figure I'll just name it whatever comes to mind and then I can defalias it or do a search and replace afterwards.

18:59 Tip: When naming, be verbose rather than terse

Prot: When in doubt, of course, be verbose rather than terse.

Sacha: Oh, yes. When you find yourself still using the wrong words to try to find it again, just add more aliases and you'll find it eventually.

Prot: More verbose. More words. All the words.

Sacha: All the words. All right. What are the things here do we want to dig into? Adopting is always an interesting challenge and it's a challenge at all levels here, right? From the user trying to figure out "How do I remember to use this keyboard shortcut?" to "I've written this new function, it's great, but I have to remember to use it." Do you have any recommendations around changing the workflow?

19:46 Tip: Iterate on your workflow in small steps

Prot: In accordance with what I said in the beginning, iteratively. Try to memorize one. You have this new function that, let's say, streamlines how you list files in a directory, whatever, I don't know. Use it. Don't have all 10 functions and try to remember them. Just use one. After two weeks, use the next one. After four weeks, use the third one, and so on. Little by little, make it something that you just do automatically, you don't think about it, with the recognition that you want to remember them all.

20:20 Tip: Make things more automatic, and use context-sensitive clues

Sacha: In fact, going on that point of automaticity, I also like making sure this stuff happens without me having to think about it. If there's a hook that I can take advantage of to just have it automatically turned on, or if there's a context menu I can add it to so that I know, okay, if I do this, then I'll see it in a shorter list. I can get to it more easily instead of having to remember how to find it and all these details. All these little ways to make it easier for myself to automatically enjoy the improvements, or at least have a chance of finding it again.

Prot: Yeah, yeah. This is in the spirit of prefix keys, with the help of the which-key package, for example, or what Embark is doing. Of course, there are different approaches. Maybe you want to set up a transient and in the given mode, you just type question mark, for example, and it breaks up your transient with what you want to do. There are various strategies you can go about to do something like that. I lost your audio, just to say. Yeah, no problem. Let's see. Of course I can sing in the meantime, but I don't think the audience will like it. Let's see. Yeah, no problem. No stress. Of course we could do this. Don't forget that there was a time in history where cinema thrived with technology like this. So it will work. Okay, I can read a little bit from the chat. So something I love doing is after I've learned that one function at the late...

Sacha: Can you hear me now? No. Test. Okay, okay, okay. Woohoo! Successful panicking. Alright. Great. Great. Magic? Something is happening? I don't know what is happening. My video is less important. It's fine. You may continue. Oh yeah, for sure.

24:48 Skill: Thinking in terms of elements

Sacha: Even just thinking, okay, here are the elements that it can work on and here are the actions that I want to associate with those elements. I guess it starts with the intuition of what are the things that I can address. And what I do is I just look at the embark source code and I'm like, oh yeah, okay, Org headings, that makes sense, and variables and all that stuff. I always like looking at people's setups. Okay, this one says you are now too quiet. Can you say something? Okay, okay, this is definitely a me problem. Hang on a second. Oh, okay, okay, okay, I think... Ah, technology. Why is it so fun? Test. Test. No, this is not right. No, no, no.

Prot: Let me know if you can hear me now. And of course, in the meantime, I can comment on the weather. I don't know if I can be heard. But in Western Europe, the temperatures are record high. And here in the mountain of Cyprus, it's like 20 degrees Celsius max.

Sacha: Okay. So did you hear any of the stream? Is Prot's audio okay now? You've got to keep talking, I guess.

Prot: Yeah.

Sacha: Oh, my goodness.

Prot: It's completely different.

26:16 Skill: Reading other people's configuration and adapting ideas to yours

Prot: "We can hear him loud and clear." Wonderful.

Sacha: Back to braindumping. Very good. So we talked about Embark and other things and practices and workflows. I learned by reading other people's configurations, but it does take a fair bit of intuition in the first place to realize this part of the configuration means this, and how to adapt that into my own workflow. Is there a way for people to develop that aside from just reading tons and tons of configs?

Prot: At some point you just have to try. You just have to be like, "Okay, this package everybody raves about, they must be doing something good. I don't know what that is, so I have to try it and see for myself."

27:07 Tip: Start with focusing on just one thing

Prot: Then for something like Embark... We are just using it as an example, but I think it's a good example for other things. Something like Embark can do a million things, but you can also use it for just one thing, right? Find the one thing that you can use it for, use it for that, then figure out what is the second thing and take it from there. The same can be said for Org and all sorts of packages.

27:33 Blog posts and videos are useful

Sacha: I find that sometimes videos are useful for it in terms of seeing it in context, but on the other hand, sometimes I don't have the patience to watch a whole video. I particularly enjoy the posts that are both blog posts plus videos, so I can just skim the blog post, copy the code without having to pause and type things in manually, but also see how it works by somebody showing me how they use something.

Prot: Yes. That's the idea.

28:09 Tip: Take notes as you learn, and ideally, share them too.

Sacha: I do want to sneak in this recommendation to share. I keep beating this drum. But whenever I write about something that I've learned, I always end up getting these comments from people who point out other things that I should check out too. So I highly recommend, whether you're a beginner or whether you're a power user of Emacs, try blogging. I am happy to add people's blogs to Planet Emacs Life so people can read your stuff. All the notes are great for both crystallizing what you know as well as possibly inviting other people to share other tips and comments that point out that what you just worked on is actually a built-in package and all you have to do is configure this. Happens to me often.

28:54 Tip: Accept being a beginner.

Prot: And what can help with blogging, especially once you are blogging about something that you know has a very high skill level, is to approach it in a diary-like way, where it's like, today I learned about such and such. I am not an expert, I am learning, and this is fun. That's your blog post. You don't have to present yourself as the foremost expert on the matter, because then of course you will have to wait many years to write that blog post.

Sacha: I think that goes under this separate intuition thing for mindset and accepting the fact that no matter how many years of Emacs experience you have, you're going to be a beginner in 90% of the things that Emacs can do. So we can totally just accept the beginner's mind. There's no need to worry about imposter syndrome because we're all like this. We're all figuring things out. If you want, you can put in a disclaimer. You can say, "I'm totally a beginner. Read this for the idea and not the Emacs Lisp style," if you're embarrassed, you're self-conscious about sharing your code. But yeah, we're all just starting out, essentially. I like the fact that people in the community are so accessible. There's no one really saying, oh, I'm an expert. You should do it. You should do it this way and only this way, because we're all aware that again, we've done it this way, but there are probably five or six other implementations that could be even better that are really out there.

Prot: Yeah, exactly. Exactly.

Sacha: Charlie says, "The leverage of blogging is unique in the Emacs community. Incredibly supportive, knowledgeable, and social group of people." That's another encouragement to go try it. That is all good. In fact, there are a few days left in this May carnival for "May I Recommend." If other people have recommendations, I'd love to hear about them too. Okay, so let's talk about... Actually, what do you want to talk about? What do you want to talk about?

Prot: Let's go and do something with the power users.

31:16 Group: Power users

Prot: With the power users, of course, you have a group that is, I would think, in some ways more diverse. Because of course there are different ways to become a power user. One, for example, is using Org more; another is using it as an IDE. So the common thread I would say here is that you are the kind of person who is digging deep. That's what you are as a power user. So if you want to become a power user, you have embedded as skills reading manuals and checking the source code, that sort of thing.

Sacha: At this point, you're like, "Emacs is going to be my tool. There's a lot of depth to it." And this is where you start reading, okay, "How do I use Org Mode?" Or "How do I set up my IDE so that it's just the way that I want it?"

32:13 Tip: Browse through package lists

Sacha: For fun, I will sometimes look through the package lists just to see what's out there that I can easily reuse. But often, it isn't even a matter of adding additional packages to your configuration.

32:25 Tip: Dive deeply into the packages you have: customization options, code, etc.

Sacha: It could just be diving deeply into the ones that you do already have, looking for options, looking for little things that you can toggle on and off, or considering how the different functions can be integrated into your workflow.

32:41 Tip: find-library gets you to the source code, occur can help you browse it

Prot: And to this end, I will add something that I do frequently because it combines the elements of what we have already covered, which is M-x find-library. You select the package you are interested in. You go there, then you do M-x occur. And you search for defcustom with a parenthesis in front. "(defcustom". This will produce an occur buffer with all the user options. So you do two things now. You learn about the user options, and you are looking at some source code. That's one way I can start reading source code.

Sacha: This goes back to why we don't just tell people... You don't like Customize, so the M-x customize + regular expression is off your list. Just look at the source code.

Prot: You'll be happier. Yeah, exactly.

33:29 Tip: You can also browse through Customize

Sacha: Browsing through Customize is also an option because it'll tell you about the things. You don't have to use the Customize interface to set it, but I have come across very interesting options that way, just clicking around.

Prot: Yeah, for sure.

Sacha: @gcentauri's like, yeah, I'm bored, M-x list-packages.

33:48 Tip: Have fun with randomness and serendipity

Sacha: Sometimes I randomize these things. I think for EmacsConf, either last year or the year before, we had random packages being displayed as a screensaver. I know people have sometimes on their dashboards, they'll display random inspirational quotes. It could be a random Emacs package. I think at one point I had it display random interactive functions, just so I could stumble across more commands. Taking advantage of serendipity can be a fun way to squeeze in a little bit of learning.

Prot: Nice, nice, yes. That's good.

Sacha: All right, so Jason Torres says, "I use custom just to explore."

34:32 Tip: Check out people's workflow descriptions and stories

Sacha: Another recommendation I'd like to put in here is reading other people's workflow descriptions. Again, going back to blogs and videos and all of that. It's because a lot of these things are not obvious from looking at the source code, but when somebody tells you a story about what problem they had and how they combined pieces of different packages to solve a problem, then it becomes a lot more real.

Prot: Yes. Plus, it puts you in the spirit of Emacs, which is you can be creative and piece together different elements of functionality and have a workflow that works for you.

Sacha: Let's try plugging in, re-plugging in my webcam. Let's see what happens.

Prot: Let's see, let's see. The moment of truth.

Sacha: Everyone will just have to imagine my eyebrows of agreement. Okay, so that's the power user. This is how you get even better at it.

35:42 Resources: manuals, Mastering Emacs, Emacs Lisp Elements

Sacha: I think Mastering Emacs would probably be like a book recommendation in this area. And for customizing Emacs and actually writing Emacs Lisp, there's your Emacs Lisp Elements book. What other things would you recommend aside from, yeah, read the intro to Emacs Lisp and the Emacs Lisp Memo for fun?

Prot: Of course, what you have listed there are all useful. The other one would be in the spirit of what we said earlier of trial and error. Learn how to, or rather get in the habit of writing little snippets of code. They don't have to be the best code of your life. Just something that gets the job done. Of course you can improve it later, but by getting in the flow of writing your own code, eventually what happens is you write better Emacs Lisp. You develop intuitions of what could go where, and eventually, before you know it, you are better at Emacs just because you were doing this little routine.

Sacha: Noticing the questions. This is also a skill. This is also something that you develop. A lot of times people do not even know what's possible because they're so used to just taking for granted that this is a limitation of the system. So sometimes we have to see somebody else, you know, fly through the code without worrying about like, okay, I have to go do this and do that and whatever. Oh, somebody says it's OBS, thank you. @ashraz has pointed out that OBS has my webcam, which is why the browser couldn't find it. So I will think with that some more, but in any case, we will continue.

37:29 Skill: Figuring out what's possible and making a habit of writing tiny functions

Sacha: Yes, so figuring out what is possible and then writing a tiny function for it and developing that habit of not tolerating these little bits of friction, I think is a skill. It's a thing you can develop.

37:45 Skill: Being mindful of what you do over and over again

Prot: Yeah, and another skill which is along the lines of writing your own code but maybe also a meta-skill is: be mindful of what you do over and over again. For example, let's imagine now you have a command that switches to the other window and then blinks the cursor or whatever, right? And these are two commands and you do them all the time. You do the one, you do the other, okay? Now you can write one command, which is a wrapper of those two, and all it does is call interactively the first, call interactively the second. Just by piecing those together you already have your own little command.

38:26 Tip: Keyboard macros can help you jumpstart custom functions

Sacha: Oh, I definitely want to point out here that you can use keyboard macros to generate the Emacs Lisp for it. So even if you're not that comfortable with Emacs Lisp, or you don't remember what the keyboard shortcuts do, you can record a keyboard macro. So you've definitely learned how to do that. And then you can get it to print out the Emacs Lisp that the set of keyboard actions ran. Or at least the Emacs Lisp to repeat the same keyboard shortcuts and then it will all figure it out. Anyway, so that's there. You can save that sequence of commands as a Lisp function in your config. So that's one thing, using keyboard macros to jumpstart your Emacs Lisp.

39:11 Tip: Use C-h k (describe-key) to describe shortcuts or menu items

Sacha: And the second thing is using C-h-K or Describe Key to see what a given keyboard shortcut or menu item will actually run. So that's all very useful stuff for figuring out the Emacs list to do something you're doing interactively.

Prot: I think that's the most used help command I do. C-h k. It's super useful all the time. It's very, very helpful. And not only you learn what command it calls, but also in which key map it is bound. So for example, C-c C-c in an Org buffer, it is telling you what the command is, and it is telling you this command is bound in the Org mode map. So if you want to change something, you know that you also have to be mindful of the key map. So there is your key map.

40:04 Tip: You can set up M-x to show keyboard shortcuts too (Marginalia?)

Sacha: Yes, it tells you other shortcuts. Oh, and along those lines, one of the M-x variants shows key bindings as well, which I recommend. If you're a power user, you'd like to become more of a power user, even a regular user, right? You want to start moving to using keyboard shortcuts for your more common commands and setting up your M-x command completion so that it hints at the keyboard shortcuts. Emacs by default also tells you about it after you run a command that had a shortcut. But at least that way, when you're looking through the command list you can see, "Oh yeah, this has a shortcut!" And then you can maybe even cancel out of your M-x and practice using that shortcut right away.

Prot: Exactly.

Sacha: And along those lines, I like using Marginalia and Consult because then I can see the command descriptions alongside the command name. So there's a little bit more detail there.

Prot: Yeah, I think you meant Vertico and Marginalia.

Sacha: Oh, yes. It's one of those things, yes. It just works with everything. So yes, Vertico for completions that show you a lot of detail, and then Marginalia to actually show the thing on the side, which is helpful.

Prot: Consult is wonderful as well, of course.

Sacha: Yes.

41:26 Resource: Emacs from Scratch series by System Crafters

Sacha: @ashraz would like to recommend the Emacs from Scratch series by System Crafters. They say it's a bit dated from 2020, but still mostly relevant in general. There are a lot of video resources out there.

Prot: That's good. 2020, oh my goodness. It's been so long, I can't believe it.

41:50 Tip: Old tutorials can still be useful, although don't treat them as the sole source of truth (things may have changed since then)

Sacha: It's really interesting because I've been trying to organize the tutorial resources that people who are new to Emacs will come across. And a lot of times, some of the Org videos are from 10, 20 years ago. But they're still valid, so we have to make sure people don't immediately get turned off by the date in the video. But at the same time, they can start to tell the difference. Okay, this stuff is still applicable. But this stuff over here, it needs to be translated into how you do it in modern times. It's a little challenging for people to navigate this.

Prot: Which of course points to another meta skill which is generally information related to Emacs is useful and it will work long into the future. But don't take a tutorial or a video as the source of truth. Always use it as a proxy. Okay, I get the idea. Now I will have to check the documentation and so on.

42:55 Skill: Finding preferred resources

Sacha: I think that part of the learning journey as a user is also finding your preferred resources. A lot of times, you're not going to learn everything the first time around. Everyone thinks in different ways. You do need to spend some time looking for the kinds of resources that jive with the way that you think, with the task that you want to do or the workflow you want to have. It's using the language at the right level for you, et cetera, et cetera. Even knowing, going in, that you're not going to find one-size-fits-all tutorial because Emacs has so many different workflow possibilities... Spending some time to figure out what you like as a tutorial or as a reference, and then going back to that again and again as your understanding develops, I think is a thing worth doing.

Prot: Yes, exactly. That's the whole point of Emacs more broadly: that it accommodates the different kinds of people because it's so customizable. If something doesn't work for you, don't try to force yourself to work the way it is. Rather, change Emacs to work the way you think.

44:12 Tip: If you find your tribe, look for ways to keep in touch with them

Sacha: On a meta note, finding people who think the kind of way you do is super helpful, like the tribe within the tribe. For example, you've got this cluster of people who like using Denote because their brain works the same way that yours does when it comes to filing their notes. Once you find that connection, finding ways to keep up with what those people are doing, and often this is RSS because that's a great way to get the updates without getting buried in email. That can be a great way to keep stumbling across things that might help you.

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

45:00 Tip: Manage unequal RSS frequencies with folders or tags

Prot: On the topic of RSS, just to say something that I learned many years ago the hard way: RSS works best if you subscribe to resources that don't post 30 or 50 or 100 articles a day. If you subscribe to the BBC or whatever, that will not work because it will crowd out the blog that posts once every month.

Sacha: What I do with that is I have different folders.

Prot: Folders, filters, etc.

Sacha: Yeah, folders or tags or whatever. So all the microblogs or all the very prolific things go into one folder, which I generally ignore because it's hard to go through.

Prot: Fair enough. Subscribe.

Sacha: Yeah, the people who post once a day or once a week or once a month or once every blue moon, then it's easier to keep up with them because it's not buried in all of that stuff. You can look into your RSS readers to support for keywords maybe in order to do some more filtering and prioritization. This is one of the things that I've always envied about people who use Gnus for reading RSS. Because there's nnrss. Then you can use Gnus scoring to prioritize the RSS items automatically for you. But that's definitely a power user thing, because it's Gnus.

Prot: I think that's a power user among power users. That's really an exception.

46:33 Tip: Doing more things in Emacs has compounding benefits

Sacha: Actually, that touches on an interesting thing about becoming more of a power user of Emacs. If you let Emacs assimilate more of your life, if you start to use Emacs for more and more things, you get not just linear improvements but compounding ones as the things that you have can interact with other things. Even just for the base case of if your to-do list is in Emacs and your coding is in Emacs, then you can create to-do items that link to your code, all the way to if your email is in Emacs, then you can make your to-do refer to your email and stuff like that.

Prot: Exactly. That's where it gets really powerful.

Sacha: If you want to get even deeper into the power of Emacs, try to push more of your life into it. I love seeing the things that people do with browsing the web in Emacs. What kinds of things do you do in Emacs that make you go like, this is where the power of having everything together works out really well.

Prot: You already mentioned them, like email in Emacs together with your agenda, but also Dired, because you can mark files and attach them to the message composition buffer. You can run a M-x shell and your three marked files in Dired, you type w or 0 w and you get their path and then you can do something with them from a shell, if you cannot do it directly from calling a shell command from Dired. There are many ways like that. The keyboard macros where you can jump from a Dired buffer to a shell buffer, or from one buffer to another. All these little things. For me, it's very powerful. You use it all the time.

48:31 Tip: Learn to think of it as just text

Prot: At some point, you don't even think about it. It's just text laid out in windows, each of which shows a buffer. So at some point, it doesn't matter if it's email or programming or prose. At some point, they are all the same. So it doesn't matter at all.

Sacha: Developing that mindset of "it's just text" and the facility for working with text, such as keyboard macros, or being able to jump around, or writing your own functions to manipulate it, or even just using isearch to go through it or using undo in different contexts. I think that's definitely something that people develop and when they develop that intuition, it really helps.

Prot: Yes, exactly. In the beginning you won't think about those linkages. They won't be obvious to you. But just be mindful that they are there. They are possible. As you use Emacs, at some point you just feel naturally about them, and they happen. You're like, oh yeah, of course that was always possible. Of course, with the benefit of hindsight... In the beginning, you will be like, "Wow, I can do that!"

49:46 Tip: Take notes along the way

Sacha: That's the other reason why I want to encourage people to take notes along the way, ideally sharing them, of course, but even just for yourself, because a lot of times you will get to the point where this is just the way you've always done it. On the other hand, if you had those notes as you're figuring out how to do it, and you share those notes, then you're leaving these breadcrumbs for other people who are traveling down the same or similar path. That's something that would be very helpful for people.

Prot: Yeah, exactly.

50:16 Tip: Explore different ways to navigate and act on things

Prot: Even if you don't have external packages... For example, a workflow that for me was so powerful that I was like "Yeah, this is the way to go" involved the grep and then editing the grep results. But even if you don't use a bespoke package for that, which of course is also built into Emacs now, the functionality, you can use the grep results just as a way to jump to the result. If you hit RET, it takes you to the buffer at the point where the result is. You can have a keyboard macro that jumps to the result, makes some edit, goes back, jumps to the next result and repeat, right? You can do that even without the package. The point is that you can collect results and edit them in like a second or a minute, whereas you would need literal hours to do that and it would be error-prone.

51:09 Tip: Learn to combine different building blocks

Sacha: Yeah, and this points to the skill of being able to see and work with different building blocks. You have a block for, this is how to navigate. There are different ways to navigate. You could navigate to something based on some matching text, or you can navigate to something based on a line. You can set up your windows so that you can switch between windows or whatever. Then if you can combine that with, okay, these are some building blocks for acting on something, or this is how I can use the kill ring to take it to... or this is how I can use registers so that I can save some text or save a position or whatever else. The more of these building blocks that you can develop slowly, because being able to internalize the concept takes time, then all these different ways that you combine it to solve a problem makes Emacs very powerful.

Prot: Yeah, exactly. That's a good way to think of it, as building blocks.

Sacha: I don't know how people will do that either, aside from read the manual for fun and watch Emacs videos and read other people's posts. Often I think, what if we make a skill tree, right? Because people like gamification... But then this is going to be a really ridiculous, large skill tree with arrows going all over the place.

Prot: No, no, you don't want to do that. It will be the RPG that never ends. There is no final boss.

Sacha: @yogi583 asks what is a built-in function's name to edit grep result in Emacs?

Prot: I don't know but what I usually do is... Grep edit mode I think. It's new, right? It's new. It's built into Emacs 31 I believe.

52:47 Tip: Get the hang of keybinding conventions

Sacha: What I think of it is I go to the grep buffer and I press C-x C-q because that's the general "toggle read only"... That's another mental concept there, right? Getting a sense of the key binding conventions that might be translated into different actions in different places.

Prot: Yes. There is an annex to the Emacs Lisp manual, the Emacs Lisp reference manual, which talks about the key binding conventions, which is very useful for people to read. Even after you read that, it's a little bit hard to reason about the key bindings if you are getting started, but trust the process. You will see the patterns as you go. Generally, you can expect C-x to be global key bindings, and C-c followed by control something to be major-mode-specific key bindings.

Sacha: One of the things I like about reading other people's configs is that they'll rebind something and I'll be like, yeah, I can totally take advantage of that keybind because I'm not using the standard one as much.

Prot: Let me tell you about one I used. Of course, there are many, but by default, you close Emacs with C-x C-c.

Sacha: Who closes Emacs?

Prot: Yeah, people who make mistakes in life, such as myself. So because I would fat finger that the whole time, you want to unbind C-x C-c and then do C-x C-c C-c then you can exit. I would do it by mistake the whole time and I would destroy whatever I was working.

Sacha: Yeah, key binding design is this whole other thing that I haven't really mastered myself either. We've talked before about making the key bindings make sense. When they're mnemonic, they're easier for people to remember, right? But this is definitely something that I struggle with.

Prot: So think of it this way, of course assuming there is a space for it or you unbind something. C-x something is a global key potentially with a prefix, as a prefix. C-x r is a prefix, C-x p is a prefix and they have global scope, right? If you are doing something that is global in nature, it should work everywhere. You may want to do the same if you are okay with overriding default key bindings, right? Otherwise, you want to do something that is more specific. C-c C-something for a mode. Again, optionally overriding what a major mode is doing. Then you have to work with that. Use mnemonics. Use words that make sense. For example, C-s is the default key for searching. M-s is the prefix for alternative search. Think of it. Alt-S, right? All the alternative kind of searches, such as M-s o, right? So you can now think of M-s and then g would be my grep. M-s and f would be my find and so on. You can think in concepts like that.

56:06 Tip: Use which-key for keybinding help

Sacha: When in doubt, keep which-key enabled so then it will remind you at least of what else you've had configured for that prefix. That's the other recommendation. which-key mode, it's built in now. Just go use it.

Prot: Yeah, which-key mode is very useful. If you are using the Embark package, it has a key that will take over C-h. So actually that works even with default. If you type an incomplete key sequence, C-h will produce a listing with all the keys that complete that sequence. So it will be a help buffer that will tell you, okay, C-x, C-h, for example, will list everything that follows C-x. And it will name the command and all that. So that's also something to consider. I think if Embark were to add the which-key functionality where it's like C-h on a timer, I think then Embark would be a straight upgrade over which-key. In that regard. So Omar, if you are listening... Asking for a friend.

Sacha: @gcentauri says, "I recommend learning how to define a key map and put it under a leader key. I have M-m as my personal key map and then the things I find very useful I add to my key map." For this one, I've been experimenting with bind-key, which makes all of this stuff much easier in terms of defining prefix key and adding a docstring and all those other lovely things.

57:41 Tip: Figure out your ergonomics

Sacha: I like your other meta tip about experimenting with how your keyboard is set up. So for example, even on my laptop... I have a ThinkPad. So even on my laptop keyboard, there's no QMK, but I can use Kanata, which you've also recommended elsewhere. to try experimenting with one-shot modifiers and home row mods or other things like that that I want to, making it easier to press key bindings that have different modifiers. I don't want to have to press ctrl and shift and super all at the same time. If I set up one-shot modifiers, I can just tap tap tap and it becomes easier to press.

Prot: Yes, exactly. That opens up a lot of possibilities in terms of mnemonics, but also in terms of prefix combinations and all that. You can go a very long way.

Sacha: And I think there's a meta thing here also about getting a sense of what would make it easier for you to be able to continue enjoying this long term? Because RSI is not conducive to enjoying Emacs long term.

Prot: No. For sure. Something that I think I learned the hard way through pain is that you want to consider your desk, how you sit at the desk - you want to consider everything, not just the keyboard. For example, I have adopted a standing desk since forever. I do that all the time. I never sit, because it works better for me. I have the keyboard set up the way that makes sense to me. I can write all day. It's what I do. I don't have any pain. Whereas before I would sit on an awkward chair, the desk was not optimized, the keyboard was definitely not something I had thought of, and I had pain. It was really difficult, and I reached the point where I couldn't write. I was like, okay, I have to quit.

Sacha: If Emacs is something that pays off better in the long term, it's good to have a long term.

Prot: Exactly.

Sacha: Speaking of my very short term, in about one minute, I'm going to go off and help with the kiddos' lunch break. I very much appreciated this brain dump. This is great. I'm going to do all the usual transcription and things like that, start pulling out some of these ideas. Chat, if you found anything super interesting that you would like fleshed out into a blog post, say it so we know what to focus on for priorities, right? This was a lot of fun. Are there any key recommendations you want people to make sure they check out or is it just generally like, everyone...?

Prot: No, I think what you have here is good because, of course, you can always say more. So I will conclude with what I started. Less is more, seriously. For life, not just for email.

Sacha: Your brain is surprisingly small. If you break what you learn down into tiny steps, you have a higher chance of it actually sticking. Once you get something in, then it makes things a little bit easier. You have a little bit more space to learn the next thing, and so on and so forth. Otherwise, if you bite off too much, you get overwhelmed.

Prot: Very nice, very nice. And that ties into the lunch break. Yes.

Sacha: All right. Thank you so much. I will skedaddle and yeah, I will do all the things afterwards. Thanks everyone also for dropping by and hanging out. All right. See you around.

Prot: Take care. Take care. Goodbye. Goodbye.

Chat

  • ChristianTietze: â€‹đŸ„
  • protesilaos: ​Hello world!
  • MichaelVash7886: ​hello Prot
  • ChristianTietze: ​In (comparatively) ice cold Germany we had ~30ÂșC this week and there's Prot with 3 layers of clothes 🙂
  • chelmikador: ​​Hello!!
  • gcentauri: ​Hello!
  • gcentauri: ​totally
  • gcentauri: ​nerd sniping minefield
  • gcentauri: ​Emacs gives us Discoverability, and learning which tools enhance it for you is really important. Consult for example, and Helpful
  • sachactube: ​​https://pad.emacsconf.org/yay-emacs
  • gcentauri: ​i was literally doing that last night before bed
  • gcentauri: ​i came across the Forms library I had no idea existed
  • CharlieBaker707: ​​edebug + ert tests changed the way I develop elisp! No longer flying blind đŸ€Ł
  • ChristianTietze: ​end-to-end tmux snapshots – you can assert on the modeline contents and other 'ui' of Emacs too, at least in terminal rendition of course
  • gcentauri: ​because in Lisp its lists all the way down :)
  • CharlieBaker707: ​​something I love doing is, after I've learned that 1 function, at a later point I'll meta-x for that package's namespace, then embark-collect into a buffer and explore what other user-facing exist.
  • sachactube: ​​ugh hang on
  • CharlieBaker707: ​Stole that trick from Prot ;-)
  • ChristianTietze: â€‹đŸŽ¶
  • sachactube: ​​hahaha, you can just keep braindumping tips while I panic
  • sachactube: ​​I will continue to panic
  • blaiseutube: ​​don't panic
  • CharlieBaker707: ​we can hear you!
  • CharlieBaker707: ​but not Prot :-D
  • blaiseutube: ​​oooh much better!
  • yogi583: ​​we cant hear prot
  • blaiseutube: ​prot is too quiet
  • gcentauri: ​@sachactube - prots audio is very low
  • renaudbussieres: ​​Is Prot only in your headphones?
  • sachactube: ​​I will look into that
  • blaiseutube: ​his audio is completely different
  • chelmikador: ​​now!
  • yogi583: ​​we can hear him
  • blaiseutube: ​yes!!!
  • CharlieBaker707: ​​loud and clear Prot!
  • MichaelVash7886: ​​all set now
  • gcentauri: ​Yes!
  • gcentauri: ​good!
  • blaiseutube: ​perfect!
  • blaiseutube: ​ooooh, Cyprus is nice
  • blaiseutube: ​Massachusetts is also 20C
  • ashraz: ​​Is prot's sound only clipping for me a bit or also for others?
  • MichaelVash7886: ​​maybe a little but it's not bad on my end
  • sachactube: ​​That was me because I panicked about audio, returned to normal levels now
  • CharlieBaker707: ​​The leverage of blogging is unique in the Emacs community. Incredibly supportive, knowledgable, and social group of people.
  • gcentauri: ​We always need beginners to show us where things actually DONT make sense! A beginners mind see's all possibilities
  • gcentauri: ​yep. "i'm bored, M-x list-packages"
  • gcentauri: ​yeah i use Custom just to explore
  • gcentauri: ​Discoverability!
  • gcentauri: ​(btw this is shoshin from elsewhere)
  • renaudbussieres: ​​"M-x apropos-user-options" is another way to browser customizable options :)
  • gcentauri: ​@sachactube we can see you in the lower right, you've somehow gone to having your video floating
  • ashraz: ​​@sachactube Your webcam is shown as an overlay over the chat, which may be the reason why it cannot be shown a second time on Firefox
  • ashraz: ​​*Chrome
  • blaiseutube: ​​BRB
  • sachactube: ​​thanks!
  • blaiseutube: ​​
. seems like a "config profiler" would be handy, to produce a human readable summary of settings.
  • ashraz: ​​I also liked the Emacs From Scratch series by System Crafters. It's a bit dated (from 2020), but still mostly relevant in general, IIRC.
  • ashraz: ​​@blaiseutube Profiler as in loading time, or in "what is actually in that profile"?
  • gcentauri: ​is that Marginalia?
  • ashraz: ​​@gcentauri Aye, marginalia shows the shortcuts.
  • gcentauri: ​not Marginalia
  • gcentauri: ​i think maybe Vertico
  • ashraz: ​​2020 predates the minad-stack (vertico, marginalia, orderless, consult, corfu), it used ivy, swiper and company.
  • ashraz: ​​But the mindset is still in that series 🙂
  • valentinoslavkin6116: ​​Yeah, emacs from scratch is pretty good. Maybe it could explain a bit more the language or the use-package macro, but it works regardless
  • MichaelVash7886: ​yeah I haven't watched the series as so much changed since then
  • sachactube: ​​blaiseutube config profiler sounds interesting, what did you have in mind?
  • yogi583: ​​whats the builtin function's name to edit grep result in emacs?
  • gcentauri: ​Need multiple skill trees
  • gcentauri: ​different character classes
  • ashraz: ​​@gcentauri Also different positions on the alignment chart.
  • bledley99: ​​Lovely people, been watching/reading you two for years. Thanks for all you do. 🙌
  • gcentauri: ​I recommend learning how to define a keymap and put it under a leader key. I have M-m as my "personal-keymap" and then the things i find very useful i add to my keymap
  • gcentauri: ​and +1 which-key
  • ashraz: ​​See `D.2 Key Binding Conventions` in the manual for the conventions (for package maintainers)
  • ashraz: ​​*in the elisp manual, not the emacs one.
  • renaudbussieres: ​​I find "leader key" strategies better too, for example the C-x keymap, displayed with which-key, is too crowded and diverse to make sense
  • gcentauri: ​yes - i had to switch to xah-fly-keys because of RSI
  • gcentauri: ​but Emacs can change and adapt to YOU! which is important
  • MichaelVash7886: ​I want to look at Meow at some point for a leader key and modal editing
  • valentinoslavkin6116: ​​Meow is really great
View Org source for this post

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

-1:-- Yay Emacs 32: Sacha and Prot Talk Emacs: May I recommend... (Post Sacha Chua)--L0--C0--2026-05-29T19:00:42.000Z

Irreal: Auto Revert Ignore

Just a quickie from Marcin Borkowski (mbork) today. Like many of us, mbork likes to turn on global-auto-revert so that any file open in Emacs that gets changed by an external process has the changes reflected in the Emacs buffer.

Sometimes, though, you don’t want that to happen. Mbork gives the example of viewing a PDF file while LaTeX is updating it. The question is: how to prevent auto revert from updating certain modes.

That turns out to be pretty easy. As usual, Emacs has us covered. The global-auto-revert-ignore-modes variable lists all the modes that should be ignored by auto revert. You can check mbork’s post for the details but it’s really quite simple: you list the modes that auto revert should ignore and that’s it.

This is, really, a niche concern but if you have it, mbork’s post tells you how to avoid it.

-1:-- Auto Revert Ignore (Post Irreal)--L0--C0--2026-05-29T14:16:05.000Z

Kemal: Brainiac v2.0 released

#emacs #brainiac #productivity #systems

Time has come to release a new version of Brainiac. The whole configuration file has been almost completly restructured, cleaned up and properly commented. So I will declare this to be version 2.0.

Following changes have been made:

  • READ.md has been extended to explain the installation and usage.
  • Readability improvements:
    • All colors decisions are now left to Modus themes, we only change typografy, e.g. underline the PROG tasks to encode work in progress.
    • Multiple Org elements were restyled, e.g. ellipsis, tags etc., to improve scanability in large documents.
    • Added the configuration for fixed and variable pitch fonts. You may set the font family to your liking.
    • Packages org-bullets, org-appear and diminish introduced.
    • Priority cookies are removed after the task is closed, to remove visual clutter.
    • When saving, the tags will be aligned automatically.
  • Added number of matches to isearch.
  • Repeaters are now visible in the agenda.
  • When jumping to items from the agenda, automatic narrow is done to improve focus.
  • Capture from anywhere is now implemented by a custom script based on org-protocol.
  • Many, many small tweaks, fixes and changes.

Get the new release from here.

Enjoy and keep hacking!

-1:-- Brainiac v2.0 released (Post Kemal)--L0--C0--2026-05-29T11:54:23.000Z

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

"...how can people keep up with what you're learning?"1

I've always kept a low profile on the Internet.  It can be a scary place!  But I've been asked to show glimpses of my online work to the people I was meeting in real life.

I agreed to chat with Sacha Chua about Emacs and Life (but not the Universe -- that'll be next time).  Emacs is worth revealing oneself for.  If people really do want to keep up with what I'm learning, they can visit here.

My init file2 shows only a small aspect of how I have Emacs configured.  You'll want to see an example of my org file(s), my diary file, and the Lisp I have tucked away under my home directory.

Aside from Emacs, my workflow relies on Vivaldi and LibreOffice, so I'll try to show what I'm doing with them, as well.  Perhaps I can provide screen recordings, too!

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

Thank you, again, Sacha!


1Sacha Chua, https://sachachua.com/blog/#ID-ec23-transcript
2https://www.emacswiki.org/emacs/RaymondZeitler
3Sacha Chua, ibid.
-1:-- Emacs -- It's Worth Revealing Oneself For (Post Raymond Zeitler)--L0--C0--2026-05-28T17:07:20.129Z

Charles Choi: Anju v1.5.0 Update

Heads up for readers of this blog who are using Anju or are mouse-curious Emacs users. I’ve recently released the v1.5.0 update for it, now available on MELPA.

Many new features and enhancements are in this update as outlined below:

Users who work with both Org mode and Markdown formatted text should find interest in the Copy as
 capability added to the Org mode context menu. This feature lets one use Org mode as the primary means of authoring text, exporting to Markdown (or another format) using a right-click mouse copy action.

img

Thanks to Marcin Borkowski whose post “Org-mode to Markdown via the clipboard”, inspired this feature.

Anju also provides a complementary command “Paste Markdown as Org” for Org mode which lets one paste copied Markdown text into an Org file, doing the conversion of Markdown to Org under the hood using pandoc.

img

In summary, this is a big release with many changes. I invite you to explore all the links above to see what’s available in Anju.

-1:-- Anju v1.5.0 Update (Post Charles Choi)--L0--C0--2026-05-28T17:00:00.000Z

Raymond Zeitler: zap-to-char M-z

Sometimes I discover an Emacs feature after an accidental keystroke. If I can remember the keystroke, I'll invoke the keystroke help (C-h k) to learn about it. Or sometimes the prompt in the mode line will suggest the function's name.

Today, the keystroke was M-z , which is bound to the function zap-to-char.

It seems to be ideal if, like me, you doze briefly while typing a senteeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee

Oops, there I go again!

To fix that I can just press M-- M-z t to delete all the trailing "e" characters.

Note that M-- is invoked by holding down the Alt key while pressing hyphen. It defines a negative prefix argument, which instructs zap-to-char to "go backward," deleting all characters from point to the specified character ("t"). I'm not sure how or why you'd want the default "forward" behavior.

What accidental keystroke have you discovered recently?

-1:-- zap-to-char M-z (Post Raymond Zeitler)--L0--C0--2026-05-28T16:30:37.052Z

Raymond Zeitler: Emacs view- Commands

A kind reader suggested I try the view-lossage command to display a list of recent keystrokes. This would be helpful for those times when I press a key accidentally and don't know what I did (as described in "zap-to-char M-z").

The output resembles what you'd get from edit-kbd-macro (assuming that a keyboard macro had been defined). This provides an alternate way to define a keyboard macro -- just select the desired portion of the output and invoke read-kbd-macro.  At this point you can "play back" those keystrokes with C-x e.

After I understood view-lossage,  I skimmed through the list of commands that start with view- (by doing M-x view- TAB). The commands view-buffer,  view-file(and variants that view in another buffer, window, frame) provide a safe (read-only) way to examine the contents of a buffer or file.

Entering M-x view-file-other-frame .emacs allows me to display my init file in a new Emacs frame and close it (by pressing "q") when I'm done with it. And then I don't have to worry about changing it inadvertently.

-1:-- Emacs view- Commands (Post Raymond Zeitler)--L0--C0--2026-05-28T16:14:29.129Z

Irreal: Zap-to-char Backwards

Today was a good Emacs day. I learned something new. Over at Ray on Emacs, Raymond Zeitler has a very nice post on using zap-to-char in reverse. He—hypothetically—was typing some text, inadvertently leaned on a key, and ended up with a long string of a repeated character at the end of his text. Something like this:

senteeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee

Here’s what I didn’t know. You can cause zap-to-char to delete characters to the left by giving it negative count argument. So in Zeitler’s example, he erases the string of e​s by calling zap-to-char as Meta+- Meta+z t.

But that’s not quite right. The problem is that it will also erase the t, which I assume was not his intention. Fortunately, there’s an easy solution that I wrote about almost 14 years ago. The problem with zap-to-char is that it does what you want it to only about half the time. The rest of the time you don’t want to delete the target character; you want to delete up to but not including that character. It turns out that Emacs has a command, zap-up-to-char, to do that but it’s not bound to any shortcut1. I have it bound to Meta+Z. It also honors the negative count argument so the correct solution for Zeitler’s problem is Meta+- Meta+Z t.

The mistake aside, this is a great post because it tells me—and maybe you—something I didn’t know: you can zap backwards.

Footnotes:

1

Happily, it’s now autoloaded by default so you no longer have to worry about that.

-1:-- Zap-to-char Backwards (Post Irreal)--L0--C0--2026-05-28T14:47:00.000Z

James Dyer: Stashing a Single File, and Why I Was Too Quick to Blame vc-mode!

In my last post I wrote about finally caving in and adding Magit to my config after years of being a contented vc-mode loyalist (VC-Mode Meets Magit - or Why I Finally Gave In!). My conclusion then was that the two complement each other nicely, Magit for repo-level operations, vc-mode for the everyday file-level stuff, commit a single file, a blame, a quick diff, C-x v and away you go. Well, I have just had a small but instructive lesson in not assuming where the limitations actually lie, because I caught myself about to reach for Magit for something vc-mode handles perfectly well!

20260528103245-emacs--Stashing-a-Single-File-and-Why-I-Was-Too-Quick-to-Blame-vc-mode.jpg

The scenario: I had a pile of changes sitting in my working tree across a few files, and I wanted to set aside the changes in just one of them, temporarily, without touching anything else. Stash a single file, in other words.

I knew that vc-mode had some stash commands through the "z" keybinding when in vc-dir, and of course you can find them through M-x by completing on vc-git-stash*, but I had only ever used it for stashing everything, straight from the worktree. So I did a quick test: in vc-mode, I moved my point over a single modified file and selected vc-git-stash, but this of course would stash everything! Well, how about a single file? I assumed that vc-mode couldn't do it and reached for magit instead!

However a little niggling doubt surfaced and I decided to have a little rummage around the vc-git code:

(defun vc-git-stash (name)
  "Create a stash given the name NAME."
  (interactive "sStash name: ")
  (let ((root (vc-git-root default-directory)))
    (when root
      (apply #'vc-git--call nil "stash" "push" "-m" name
             (when (derived-mode-p 'vc-dir-mode)
               (vc-dir-marked-files)))
      (vc-resynch-buffer root t t))))

It runs git stash push -m NAME and, if you are inside a vc-dir buffer, it appends the list of marked files as a pathspec. Which means a single-file stash is built right in, no Magit required!

  1. Open vc-dir with C-x v d (or C-x p v for the project-wide view)
  2. Move point to the file you want to set aside and press m to mark it
  3. Press z c, type a stash name, hit return

And that is it, git stash push -m "your name" -- the/marked/file runs under the hood, that one file's changes are tucked away, and everything else in your working tree is left exactly as it was. Mark two files and it stashes two, mark none and it stashes the lot, the marking is the whole mechanism.

To bring it back, z p pops a stash (it prompts you with a completing-read list of what is there)

This is almost the inverse of my last git post. Last time I went looking for vc-rebase and there genuinely was not one, a real git-specific gap that vc-mode does not fill, and off to Magit I rightly went. This time I assumed the same shape of limitation and assumed wrong, the feature was sitting there in vc-dir the whole time (and actually was pretty obvious really),

So, vc-mode really is quite capable for file-level git work, single-file stashing very much included, and I should be slower to assume "git-specific" means "Magit only". Magit is still there for the repo-level heavy lifting, but for tucking one file out of the way, C-x v d, m, z c, done, no need to leave the comfort of the built-in tooling at all.

I do enjoy these little corrections, each one teaches me a bit more about where the seams in Emacs version control actually are, and occasionally, that the seam I thought I had found was never there in the first place!

-1:-- Stashing a Single File, and Why I Was Too Quick to Blame vc-mode! (Post James Dyer)--L0--C0--2026-05-28T09:32:00.000Z

Andros Fenollosa: Playing chess online with Emacs

Every now and then I like to play a game of chess with my colleagues at the office, without ever leaving my favourite Elisp interpreter. Emacs has a really good package for this, chess, which supports several ways to play: against the machine, over a local network, against internet chess servers (ICS), and even through IRC (I am proud to say I finished implementing that last feature myself). You can check out the official documentation.

Chess board in Emacs

So I would like to share a brief introduction to playing chess over a network from Emacs.

Local network game

Lets you play directly between two Emacs sessions over TCP. You can use it to play with a friend on the same local network or VPN.

Launch it with:

C-u M-x chess RET network RET

On startup it asks which role you want:

  • Server: opens a local port and waits for a connection. Uses open-network-stream-server (or nc -l -p as a fallback if not available).
  • Client: prompts for a host and port, then connects.

Internet chess servers (ICS)

Maybe you have a favourite online chess provider, or you want to test your skills against players from around the world.

Launch it directly with:

M-x chess-ics

Connects to real ICS servers. The preconfigured ones are:

Server Port
freechess.org 5000
chessclub.com 5000
chess.net 5000
chess.unix-ag.uni-kl.de 5000
oics.olympuschess.com 5000

Supports login with a handle and password.

Playing through IRC

To play over IRC, run:

M-x chess-irc

It will connect to your configured IRC server, then ask for your opponent's nick. Your opponent needs to do the same on their end. No worries about privacy: the game uses private messages.

Note: this feature is part of my Pull Request, so if you do not see it, you may need to update your chess version or build it from the repository.

Extensions for modern platforms

There are other platforms you can play on using external packages:

Final notes

My configuration:

(use-package chess
  :ensure t
  :config
  (setq chess-images-separate-frame nil) ; Display the board in the same frame
  (setq chess-images-default-size 100))  ; Piece size in pixels

One last piece of advice: play against humans. The AI is quite easy, and while winning is fun, it is not much of a challenge. You will also get to meet more people that way. Checkmate!

I hope you enjoy your chess games inside Emacs as much as I do.

-1:-- Playing chess online with Emacs (Post Andros Fenollosa)--L0--C0--2026-05-28T07:28:52.000Z

Irreal: Rejecting Emacs Bankruptcy

Last week I saw this post by Case Duckworth about Emacs bankruptcy but this post isn’t really about Duckworth’s post. Rather, it’s about the whole notion of Emacs bankruptcy and whether it’s something we should embrace as a routine activity. Some writers view it as part of the cycle of our Emacs life and recommend it as a regular activity.

As I wrote last year, my init.el is an organic entity that grows and adapts as my needs change. Sometimes I delete configurations or packages that I no longer use but most often I add a configuration or package as my needs change or I learn something new. I’ve put a lot of work into evolving my configuration and I can’t think of any reason that I’d want to abandon all that work and start over. Much better to fix the parts that need fixing and save the parts that are working.

My configuration is by no means a carefully considered project that has grown according to some master plan. Rather, it has evolved to meet my changing needs and newfound knowledge. Sometimes there are experiments that don’t work out and when that happens, I simply delete the offending lines and keep going.

At no point have I ever felt the need to just quit and start over. That strikes me as crazy. It is, I suppose, an Emacs specific example of the urge to scrap an existing system and rewrite it. As Joel says, that always ends in tears.

The TL;DR is that I reject the idea of Emacs bankruptcy and think that in almost every case, you should too.

-1:-- Rejecting Emacs Bankruptcy (Post Irreal)--L0--C0--2026-05-27T14:55:42.000Z

Charlie Holland: space-tree: Workspace Management Trees in Emacs

1. TLDR   tldr

space-tree (see code on GitHub) is a tree-based workspace manager for Emacs. Workspaces are a battle-tested UX concept across operating systems, but in Emacs and most OSes alike, they're flat: you get a row, a grid, or a numbered list, but never a workspace inside a workspace. My requirements for a workspace manager were arbitrary-depth nesting, no naming tax, no mandatory persistence, no per-workspace buffer scoping, and a build that leans on Emacs's existing window-state primitives. The cognitive-psychology case for hierarchical organization turns out to be unusually robust: working-memory ceilings (Cowan 2001), expert chunking (Chase & Simon 1973), and direct gains in recall (Bower et al. 1969) all support the idea that a user-authored tree is easier to hold in mind than the same work flattened into a list. The feature matrix places space-tree as the only workspace manager in this survey with arbitrary-depth structure, optional naming, and a deliberately session-only memory model. The implementation is a small amount of Elisp built on window-state-get / window-state-put, with a nested hash table for the tree shape, a flat hash table for window-state snapshots, and a sparse hash table for optional names. Getting started is a use-package block plus a Super-key keymap.

2. About   emacs workspaceManagement tooling

space-tree-banner.jpeg

Figure 1: JPEG produced with OpenAI gpt-image-1

When we use our computers, the vagaries of day-to-day activities fill our displays with an unbounded number of applications. The chaos here has led to an overwhelming number of 'workspace management' tools.

I see these tools pop up everywhere in my daily computer use. macOS and Windows have workspace management solutions out-of-the-box. Linux has the venerable i3 (and btw, Aerospace is a great alternative for macOS users).

We see these solutions pop up even at the application level. Web browsers have tab-groups, and some, like Vivaldi 💜, even have first-class workspaces. Most complex applications like browsers, IDEs, DAWs, and image-manipulation programs also offer workspace management at the 'frame' level, where each visible frame is typically scoped to one or a set of projects.

Even AR devices (I'm looking at you Apple Vision Pro), offer workspace management, albeit in a hilariously silly way: the advent of AR technology has enabled you to misplace applications all around your house. You might leave your Chef in the kitchen, your CouchDB on the sofa, your Brew in the beer fridge, or (worst of all) your git porcelain in the bathroom.

Of course, Emacs offers several workspace management tools. Besides the built-in tab-bar, there is a delicious cornucopia of 3rd party solutions (7 of which are discussed here). When you think about it, robust workspace management is more important in Emacs than anywhere else, especially for those of us who try to stuff the kitchen sink in there. The more concerns being handled by Emacs, the greater the burden on organizing and navigating those concerns. But most of Emacs's native and 3rd party solutions lack the ability to organize workspaces hierarchically.

Although I'm typically against hierarchical organization, for workspaces management I think it makes perfect sense. After all, workspace management tools are providing some digital simile for how we might organize things in the physical realm.

Think about how you organize things in your dwelling: a house has rooms, rooms have shelves, shelves have drawers. If you've ever heard the name 'Marie Kondo', then you have likely embraced that drawers too can have dividers. These can be commandeered for smaller drawer-within-a-drawer spaces the moment your proliferation of joyful treasures warrants a subdivision.

Physical space, when we organize it well, is recursive or tree-like. Digital workspaces, somehow, almost never are, and that's why I created space-tree, the subject of this post.

3. The workspace, an old idea   workspaceManagement

The "workspace" is an old, battle-scarred UX concept. Whatever you call them (virtual desktops on Windows, Spaces on macOS, workspaces in i3, sway, and GNOME) every major OS has shipped and continues to ship some version of the idea.

When the screen real estate runs out, we don't grow the screen, we shard it into workspaces. You get tidy partitions of the layouts you'd like to keep around, and you can switch between them with a keybinding or gesture that (should) feel speed-of-thought and reflexive.

Workspaces work because they are simple. Complex work involves more state than a single screenful can hold. Consider what I'm working with right now as I add this to my blog:

  • When I'm fixing a failing test in space-tree, I'd like the test runner visible, the test source visible, the implementation visible, and a place to read stack traces.
  • When I'm writing this post, I'd like the org file and the rendered preview.

The workspace exists because human working memory cannot hold the inventory that human work demands, so we ask the computer to hold it for us.

i3 users will recognize a slightly more aggressive version of the idea. Workspaces in i3 don't just hold a frozen tableau of windows. Each one is addressable, meaning it has a stable identifier you can jump to directly. With one keystroke, you teleport to a labeled context (`mod+1` to "browser", `mod+2` to "editor", `mod+3` to "terminals"). In this way, the cognitive cost of task-switching is reduced to the pressing of a single key. Once that cost collapses, you start partitioning more aggressively, because the cost-benefit of giving a sub-task its own workspace flips in your favor.

But what every OS workspace manager has in common is that the partition space is flat. You get a row, or a grid, or a numbered list, but you don't get a workspace inside a workspace. If a sub-task spawns its own sub-sub-tasks (and complex work always does), you run out of luck.

4. Workspaces in Emacs   emacs comparison

Emacsapiens have implemented the workspace notion so many times that "yet another workspace manager" is a respected subgenre on the various emacs wikis, threads, and servers. I almost called this package YAWM, but space-tree sounded way cooler 😉.

Each workspace management package in Emacs solves a slightly different facet of the same underlying problem, and each one implements its author's particular taste and workflow. The pile is large, and so a survey is in order before I justify adding to it.

  • tab-bar-mode — Built into Emacs since version 27. A flat row of tabs across the top of the frame, where each tab holds a window configuration. Tab-switching is keyed by index or name. Persistence comes via desktop-save-mode.
  • eyebrowse — A flat, numbered list of window configurations, frame-scoped, intentionally lightweight. This in my opinion is the granddaddy of the "virtual desktops in Emacs" idea, and was my daily driver for years until I built space-tree.
  • perspective.el — Buffer scoping by named workspace. Each perspective restricts the buffer list to a subset, so switch-to-buffer only sees what's "in" the active perspective. Optional persistence across sessions.
  • persp-mode — Independent fork with overlapping goals: buffer scoping plus window configurations, with per-frame perspectives and richer persistence.
  • activities.el — alphapapa's modern take. An "activity" bundles frames, tabs, windows, and buffers, with snapshots saved as bookmarks (so you get cross-session persistence).
  • burly — Also alphapapa's. Treats window/frame/tab layouts as bookmarks, leveraging the built-in bookmark machinery for restoration. More of a primitive than a workspace manager per se — activities builds on top of it.
  • beframe — Protesilaos's per-frame buffer-list scoping. Each frame sees only the buffers opened from it.
  • workgroups2 — A long-running spiritual successor to elscreen, with named saveable workgroups.

These are well-built tools, each by an author whose taste I respect, and each solving a real problem. I like and have used all of them, and if you're sick like me, I recommend you try them all too đŸ€Ș.

None of them, however, after a fair amount of usage, was quite right for me. I'm a little precious, like Goldilocks, when it comes to this sort of thing, so I decided to clearly lay out my minimum viable needs before whipping up my own porridge.

5. My needs, plainly stated   workspaceManagement

When I sat down to figure out why none of the above stuck, I realized I had a handful of stubborn requirements.

5.1. Arbitrary depth, not arbitrary width

I want workspaces to nest, the way drawers nest inside cabinets. A bug fix needs one space. A multi-file refactor with tests needs a parent space with three or four children. A weeks-long investigation into a sub-system might want a whole subtree. Flat workspace lists make me flatten by force. Either I over-structure the simple task to match the list's grain, or I under-structure the complex one and fail to manage that complexity. I've used i3 and macOS Spaces for years, and the recurring frustration is the same: when the work has shape, the workspace manager should let me carry that shape, not iron it out.

5.2. No naming tax

Most of my workspaces don't deserve names (sorry, not sorry). Typically I create a workspace for a quick jaunt down some rabbit hole, then it disappears, like a sticky note. Asking me to name one at creation time is friction, and my lazy self will pay the friction by not creating the space at all. The consequence is that my main workspace keeps getting cluttered, which means I'm back to staring at a single screenful of chaos. If a space earns its name, I'll give it one. Until then, I'm content to give it a number.

5.3. No mandatory persistence

Again, most of my workspaces are ephemeral. Yesterday's tree is an entirely different species from today's, and in fact it changes from hour to hour.

Persistence is a useful feature, and the tools that offer it (activities, persp-mode, perspective.el) are valuable for people whose workflow benefits from picking up exactly where they left off.

But for me, the cost of bookkeeping (managing the saved set, pruning stale entries, choosing what to restore on start) has consistently exceeded the value of the restoration itself. I'd rather pay nothing and rebuild a tree with a flick of my wrist. Incidentally, I've noticed issues persisting and restoring buffers of certain types, but I won't detail that as it's likely a skill issue (bro) on my part. Curious if any readers have experienced that Restoration VaporwareTM.

5.4. No workspace scoping

A workspace, to me, is a purely visual contract. It says "here is a configuration of windows and the buffers they're displaying. Restore them when I return to this space".

Some of the tools in the survey above (perspective.el, persp-mode, beframe) take the abstraction a step further by scoping the buffer list itself per workspace, so that switch-to-buffer only sees the buffers that "belong to" the active workspace.

This is a legitimate feature, and the people who reach for it love it, but it doesn't match how I work. I want any buffer reachable from any space.

recentf, bookmark-jump, consult-buffer should always present the same cosmos of buffers regardless of which space I happen to be in. Partitioning that cosmos by workspace adds friction to the "let me just pop into this other thing for thirty seconds" trick, which happens to me constantly, and which is one of Emacs's best facilities.

For the cases where I genuinely want task-scoped views of buffers and files, Emacs already has better-targeted tools that don't require me to commit to a partition up-front. project.el scopes buffer searches, file operations, and grep to the current project. consult-buffer-narrow lets me filter the buffer list interactively by source (file buffers, hidden buffers, bookmarks, project buffers, etc.). recentf remembers what files I've visited recently.

These flexibly scoped tools compose naturally with whatever space I'm in. While space-tree handles the visual layer, the buffer-discovery problem is someone else's job, and Emacs has plenty of someones for it.

5.5. Built on what's already there

Whatever I built, I wanted it to lean on Emacs's existing window-state primitives, with no shadow buffer model (the way perspective.el and persp-mode maintain a parallel buffer list alongside Emacs's own) and no parallel notion of "what the frame looks like" (in fact, I don't want to use multiple frames at all because I prefer the 'single pane of glass' vibe). Emacs already knows how to capture and restore a window configuration. A workspace manager that introduces a new abstraction for that is, for my use case, doing more than it needs to.

6. Cognitive Psychology: Why Nesting Works   cognitivePsychology workspaceManagement

When developing space-tree, I was worried that the "tree" might just be a programmer's reflex. Everything looks like a tree once you've spent enough time staring at file systems, abstract syntax trees, and org-mode outlines. Maybe I was just imposing a preferred data structure on a solution that doesn't need it đŸ€”.

I did some research on this, and to my surprise, the cognitive psychology literature has been making the case for hierarchical organization of complex state since the 1950s, with unusually robust empirical support. Because the use-case of workspace switching needs to occur at the speed of thought, any reduction in the burden our naturally limited working memory is useful, and this burden is what the hierarchy alleviates.

I'll stop that hand-waving and get down to the evidence.

6.1. The working-memory ceiling

George Miller's 1956 paper, "The Magical Number Seven, Plus or Minus Two", is among the most-cited pieces of cognitive psychology ever written. The key finding was that human working memory holds roughly 7±2 discrete items. Nelson Cowan's 2001 review, "The magical number 4 in short-term memory" (Behavioral and Brain Sciences), was even more admonishing of our feeble brains' working memory. Cowan found that when you control for rehearsal and chunking, true working memory capacity is more like three to five items. (I did look for an opportunity to use the 6/7 meme here, but I'm afraid it's not in the data, sorry 😂.).

A non-trivial dev session has many more than five open buffers at any given moment. A flat workspace list, viewed through this lens, is a UI that places unrealistic burden on working-memory. In Emacs, you hit the working memory ceiling almost immediately, and you don't go soaring through it like some hopeful Charlie Bucket in a great glass elevator. You smack into it and get grounded very quickly.

6.2. Chunking is how experts cheat

The classical escape from the working-memory ceiling is chunking: recoding several items into a single higher-order unit.

William Chase and Herbert Simon's 1973 study (Cognitive Psychology) is the canonical demonstration. They showed mid-game chess positions to expert and novice players for five seconds, then asked them to reconstruct the board. Experts were vastly better, until the positions were randomized, at which point the experts' advantage evaporated. The difference wasn't memory capacity, but rather the ability to chunk a meaningful position into a handful of higher-order patterns.

Experts don't remember more items. They create and remember more chunks.

A hierarchy is, structurally, an explicit chunking system: each interior node is a chunk that compresses everything beneath it. When I bind s-2 to the "investigation" subtree, I'm holding one chunk in working memory, and the many sibling spaces of the "investigation" subtree are out-of-mind until I need them.

6.3. Hierarchical organization directly improves recall

The most quotable single study is Bower, Clark, Lesgold and Winzenz (1969), in the Journal of Verbal Learning and Verbal Behavior. They gave subjects 112 words to memorize, either in a flat random list or in a four-level conceptual hierarchy.

The words and study time were held constant across all subjects. Organization (by hierarchy) was the variable.

Subjects given the hierarchical organization recalled two to three times more words on free recall, and the advantage compounded across trials.

6.4. Complex work is already hierarchical

The other side of the argument is that the tasks we want workspaces for are already hierarchical.

Newell and Simon's Human Problem Solving (1972) established goal-subgoal decomposition as the canonical model of how humans actually attack non-trivial problems. Annett and Duncan's 1967 paper introduced "hierarchical task analysis", which is still standard practice in aviation, anesthesiology, and other domains where the consequences of dropped state are literally catastrophic. And Karl Lashley's 1951 paper, "The Problem of Serial Order in Behavior", made the parallel argument for skilled motor sequences: they are not flat chains, but hierarchically planned structures.

When a flat workspace manager meets a naturally hierarchical task, somebody has to pay for the mismatch, and that somebody (until space-tree 😉) is the developer, who awkwardly projects the natural hierarchy of their work onto the incidental flatness of the tool.

6.5. Cognitive Load Theory names the cost

John Sweller's Cognitive Load Theory (originating in his 1988 paper in Cognitive Science) gives a name to that cost. Working memory load splits three ways:

  • Intrinsic load — the essential complexity of the task itself.
  • Extraneous load — complexity imposed by how the task is represented.
  • Germane load — complexity that goes into building useful schemas.

A flat workspace list applied to a hierarchical task adds extraneous load, because the developer is spending working memory on the workspace manager's structure rather than the intrinsic load on the work itself. Hierarchical organization, where the user authors the tree-like structure, eliminates that overhead by letting the representation match the task. Authoring that tree structure is german load, and space-tree greatly reduces it.

6.6. Hierarchies match the workspace management use case

I'd be misrepresenting the literature if I said hierarchies are always the right choice. The HCI research on menu depth versus breadth (Kiger 1984; Snowberry, Parkinson & Sisson 1983; Norman 1991) generally finds that broad-and-shallow menus outperform deep-and-narrow ones when the user has to navigate someone else's hierarchy by visual scanning. Hick's Law, going back to 1952, also reminds us that reaction time scales with the logarithm of the number of choices: many short decisions can be slower than one well-displayed wider one.

So the honest claim is that, conditionally, hierarchies are the right choice when

  1. the underlying task has hierarchical structure,
  2. the user authors and controls the structure rather than navigating someone else's,
  3. each level fits within the working-memory ceiling, and
  4. recognition-based traversal is supported, so the user is recognizing rather than recalling (Mandler 1980).

space-tree is designed against these four conditions intentionally.

  • Debugging, refactoring, and investigation are hierarchical tasks (condition 1).
  • Users author their own trees and prune them freely (condition 2).
  • No level needs more than a handful of siblings in practice, because deep trees express richness as depth rather than width (condition 3).
  • And the modeline lighter shows the current branch and its siblings at each level, so the user is recognizing their position rather than recalling it (condition 4).

That doesn't make space-tree the right tool for everyone. But it does mean the "tree" part is not just a programmer's reflex. As I've found, there's a reasonable amount of empirical gravity around the idea that complex work, organized in a tree the worker authored themselves, is easier to hold in mind than the same work flattened into a list.

7. The field, at a glance   emacs comparison

To help explain what space-tree offers amongst a large field of workspace management tools in Emacs, I've included a feature matrix. This is a crude summary of nuanced tools, and I encourage the curious reader to consult each project's README for a fairer picture.

Package Structure Naming Scope Persistence Extra deps
tab-bar-mode flat optional windows via desktop none
eyebrowse flat optional windows optional none
perspective.el flat yes buffers + windows yes none
persp-mode flat yes buffers + windows yes none
activities.el flat yes frames + windows yes (bookmarks) burly
burly flat yes windows + frames via bookmarks none
beframe per-frame n/a buffers per frame n/a none
workgroups2 flat yes windows yes none
space-tree arbitrary optional windows session-only none

You can see that space-tree is a different flavour from the same bag of sweets.

The cell that earns space-tree a special place in the matrix is the first one (Structure is arbitrary). Every other tool gives you a flat list with various toppings, but space-tree's distinguishing trait is that the workspace structure is a tree.

8. How space-tree works   emacs dataStructures

The implementation is small, by design. The whole thing, including docstrings, is ~680 lines of code at the time of this writing, and it could have been smaller if I'd used dash or ht.

At its core, space-tree is two simple ideas (plus a sparse third for names):

  1. A tree of addresses. Each space is identified by a list of integers, read left to right as a path down the tree. (2 1 3) means "start at top-level space 2, descend to its 1st child, then to that child's 3rd child." The tree itself lives in a nested hash table whose values are hash tables, recursively. Creating a space writes a new key, and deleting a space removes a subtree.
  2. A hash table from address to window state. When you switch to a space, the saved state is restored; when you leave one, the live state is snapshotted back. Branching creates a new address and seeds it with a fresh layout.

The native Emacs API is doing all the heavy lifting of storing and restoring the window layouts. The "window state" is what the built-in window-state-get returns, and what window-state-put accepts. These are the canonical Emacs primitives for serializing the arrangement of windows and their buffers in a frame, available since Emacs 24. space-tree adds no new representation of what a layout is. The only thing it adds is a shape for organizing many layouts at once.

To make the two ideas concrete: suppose a user has carved out the following spaces over the course of a session.

1
├── 1.1
│   └── 1.1.1
└── 1.2
2

The three hash tables of space-tree then look like this, assuming the user has named two of the spaces:

;; space-tree-tree              — the *shape*, as a nested hash table.
;; Keys are integer space numbers; values are child hash tables.
{
  1 → {
        1 → { 1 → {} },
        2 → {}
      },
  2 → {}
}

;; space-tree-address-wconf-tbl — the *snapshots*, as a flat hash table.
;; Keys are address lists; values are what `window-state-get' returns.
{
  (1)     → #<window-state ...>,
  (1 1)   → #<window-state ...>,
  (1 1 1) → #<window-state ...>,
  (1 2)   → #<window-state ...>,
  (2)     → #<window-state ...>
}

;; space-tree-space-name-tbl    — the *names*, as a flat hash table.
;; Keys are address lists; values are user-supplied display strings.
;; Sparse: only the spaces the user has explicitly named appear here.
{
  (1)   → "main",
  (1 1) → "investigation"
}

The first table encodes where the spaces sit, the second what each space contains, and the third which of them have been a named.

Switching to a space simply looks up its address in the second table and passes the result to window-state-put. Creating a child is simply walking the first table to the parent, adding a new key, and rendering a 'blank' (scratch buffer only) workspace. Deleting a space drops its structural entry. The names table is sparse (and rarely used ib my experience). Unnamed addresses simply don't appear in it, and the modeline falls back to the numeric label.

Strictly speaking, the structural table is redundant because each address is itself a root-to-node path, and the keys of the second table already encode the tree. It's there as an index for constant-time sibling enumeration. Honestly though, at realistic scale, it is a fair objection that this optimization doesn't matter. I'm just hash-table crazy 😝.

The total inventory of state:

  • one hash table for the structural tree
  • one hash table mapping address to window-state-get output
  • one hash table mapping address to user-chosen name (optional, sparse)
  • a list of recently visited addresses, for "last space" toggling
  • one variable holding the current address

8.1. What you do with it

Most of the time, you're doing one of four things:

  • creating a sibling at the current level — space-tree-create-space-current-level
  • branching into a child — space-tree-switch-or-create with a deeper address, or the space-tree-sub-N / space-tree-sub-sub-N convenience wrappers
  • jumping laterally between siblings — space-tree-go-left, space-tree-go-right, or space-tree-switch-current-level
  • jumping to any other space by address — space-tree-switch-or-create (and the conveniences space-tree-to-N, space-tree-switch-space-by-digit-arg, space-tree-switch-space-by-name, space-tree-go-to-last-space). Partial addresses resolve to the most recently visited descendant, so asking for (1) after you've been at (1 1) lands you at (1 1) rather than the parent itself.

Spaces start unnamed, but you can name one at any point with space-tree-name-current-space, after which it appears by name in the modeline and is reachable directly via space-tree-switch-space-by-name. When you're done with a branch, you can prune it with space-tree-delete-space. When you've built a layout you like, you can use space-tree-copy-workspace and space-tree-paste-workspace to duplicate it elsewhere in the tree. The modeline indicator (space-tree-modeline-lighter) shows your current position at all times, so the tree, and the branch you're on, are always visible, never something you have to remember.

Concretely: Let's say I'm trying to fix a failing test.

  • My runner is in space 2.
  • I branch into 2.1 to open the test source, and again into 2.2 for the implementation.
  • Then I create a sibling 2.3 for the stack-trace logs.

Each space preserves its own window layout, wherever it was left off.

When I fix the bug, I can delete all the spaces in 2 with space-tree-delete-space on each one, and the whole subtree goes with it.

9. What space-tree Doesn't Do   emacs tooling

space-tree manages window configurations only. It does not scope your buffer list, restore frames across sessions, integrate with desktop.el, or coordinate with project.el.

This is deliberate. The packages I cited earlier solved a problem I didn't have (buffer scoping, persistence) by also solving the one I did (window layouts), and the bundling made it hard to mix-and-match. space-tree's restraint is its compatibility: it does the one thing I wanted, and it stays out of the way of anything else I'd like to compose with.

10. Getting started   emacs installation

space-tree lives on GitHub. The README has the full command reference; here is a worked example of the install plus a full keymap with general.el that mirrors what I run in my own config.

(use-package space-tree
  :ensure (:host github :repo "chiply/space-tree")
  :config
  (space-tree-init)

  ;; Top-level spaces with Super key + number
  (general-define-key
   "s-1" #'space-tree-to-1
   "s-2" #'space-tree-to-2
   "s-3" #'space-tree-to-3
   "s-4" #'space-tree-to-4
   "s-5" #'space-tree-to-5
   "s-6" #'space-tree-to-6
   "s-7" #'space-tree-to-7
   "s-8" #'space-tree-to-8
   "s-9" #'space-tree-to-9

   ;; Second level (within current top-level space)
   "s-a" #'space-tree-sub-1
   "s-s" #'space-tree-sub-2
   "s-d" #'space-tree-sub-3
   "s-f" #'space-tree-sub-4
   "s-g" #'space-tree-sub-5

   ;; Third level (within current second-level space)
   "s-A" #'space-tree-sub-sub-1
   "s-S" #'space-tree-sub-sub-2
   "s-D" #'space-tree-sub-sub-3
   "s-F" #'space-tree-sub-sub-4
   "s-G" #'space-tree-sub-sub-5

   ;; Navigation
   "M-S-<tab>"   #'space-tree-switch-space-by-name
   "M-<tab>"     #'space-tree-go-to-last-space
   "C-M-<tab>"   #'space-tree-go-right
   "C-M-S-<tab>" #'space-tree-go-left

   ;; Delete current space (the command defaults to the current address)
   "s-_" #'space-tree-delete-space)

  ;; Evil/vim-style bindings
  (general-define-key
   :states '(normal visual)
   :keymaps 'override
   "gt" #'space-tree-switch-current-level
   "gT" #'space-tree-switch-space-by-digit-arg
   "g+" #'space-tree-create-space-top-level
   "gn" #'space-tree-create-space-current-level))

Drop the Evil block if you don't use Evil, and swap the Super-key prefix for whatever modifier your OS doesn't already consume (Hyper, Meta-Super, or just plain Meta with a different chord).

If you try it and something is broken, open an issue. If something is missing, open one with a feature request, or open a PR.

To the authors of the packages I surveyed: thank you. I learned something from each of yours before I built mine, and the fact that there is a respected subgenre of workspace managers in Emacs is, frankly, one of the things I love about this universe.

-1:-- space-tree: Workspace Management Trees in Emacs (Post Charlie Holland)--L0--C0--2026-05-27T11:32:21.000Z

Protesilaos: Emacs live with Sacha Chua about ‘May I recommend’ on Thursday 28 May 17:30 Europe/Athens

Raw link: https://www.youtube.com/watch?v=xl-ifABU45A

Tomorrow, the 28th of May 2026 at 17:30 Europe/Athens time, I will join Sacha Chua’s live stream.

We will talk about the Emacs blog carnival topic for this month, which is “May I recommend”. The video will be recorded for future reference.

I already have some ideas and am looking forward to our chat!

-1:-- Emacs live with Sacha Chua about ‘May I recommend’ on Thursday 28 May 17:30 Europe/Athens (Post Protesilaos)--L0--C0--2026-05-27T00:00:00.000Z

Irreal: Adventures On Emacs’ Event Horizon

Regular readers will be familiar with my occasional posts concerning my old pal Watts Martin’s journey into the Emacs event horizon. When he began, he swore that he would not be one of those “everything in Emacs” folks. He still (barely) hasn’t succumbed but the Borg are smiling and mumbling something about resistance and futility.

His latest step into the unknown frontiers of the black hole is adopting mu4e as his email client. It’s not an uninformed decision. Martin has tried lots and lots and email clients and mostly hates them all. As a long time Mac Head, he doesn’t care for the mu4e UI—it is, he says, the opposite of what a proper Mac app UI should be. But yet. It does have a lot of features that other mail clients don’t have. You can take a look at his post for the details.

Martin complains, rightly, that mu4e is hard to configure, especially considering that you also have to deal with isync/mbsync or something similar to retrieve email from it’s IMAP server. Longtime readers will remember my own struggles with that. I managed to avoid one of the problems that Martin dealt with by forwarding all my email accounts to a single account from which I retrieve them.

That saves a lot of trouble on the mbsync end but still allows me to handle each account separately within mu4e. If I answer an email, mu4e looks at the address the email was sent to and automatically sends it from the right address. If I initiate an email, it’s a simple matter to arrange it to be sent from any of my accounts.

Martin’s post on mu4e is actually a pretty good review of the app and worth looking at if you’re an Emacs user looking for a new email client.

-1:-- Adventures On Emacs’ Event Horizon (Post Irreal)--L0--C0--2026-05-26T15:10:19.000Z

TAONAW - Emacs and Org Mode: Using Denote for Email: A manual workflow

As I started to write more emails to other bloggers, the annoyance with macOS’ built-in email client grew. It wasn’t just the fact that it has small text that’s hard on the eyes especially on the harsh white background anymore; it just started to feel restricting.

Emacs is my natural writing environment for longer texts, like blog posts or the kind of emails I end up writing.

I’ve considered mu4e before, but setting it up seems a daunting overkill: the place I would benefit from mu4e is work, but I’m blocked by Microsoft-only 2FA authentication, so I have to stick with Outlook; meanwhile, for the three or so emails I write to other bloggers, it doesn’t require such heavy lifting.

One day about two weeks ago, I just fired up Denote, and suddenly it clicked. Denote, when you invoke it for a new note, asks for a directory - so I created an email directory in my parent Notes folder, and started writing. For a title, I use the subject, and the keyword is reserved for the recipient.

Now my eyes thank me again, as some of these emails can take an hour (and more even) to write. Links are a breeze to include, and quotes - which I use heavily in emails - are just a keyboard press away. It also looks nice when I go to the email directory and see all my drafts there, organized nicely as Denote knows how to do.

Since Denote doesn’t handle emails, for this I simply export the org file to HTML, and then with Dired (which opens in the same directory as the note I’m writing by default), I open the HTML file with my browser. From there, I copy-paste into Apple Mail, which acts as a proofread enhancer with Grammarly going to work there (this is something I’d miss if I were to use mu4e, though I could probably use Harper).

It’s a bit of a manual process, and I do need to delete the HTML files from the email directory every now and then, but for now it’s fine. It’s probably easy enough to create some shortcut that will open these HTML files directly with Mail instead of copy-pasting1 though.

Footnotes

1 Opening an HTML file with Dired with ! open -a Mail would make sense, but it opens Mail with the HTML file as an attachment, not as the body of the text.

-1:-- Using Denote for Email: A manual workflow (Post TAONAW - Emacs and Org Mode)--L0--C0--2026-05-26T13:44:27.000Z

Marcin Borkowski: Ignoring pdfs when auto-reverting files

I quite like the global Auto Revert mode. It is especially useful when I something else than Emacs sometimes changes my files. (I bet some readers immediately thought about the now-fashionable agentic coding, but plain old git switch is enough!) It has one drawback, however. I hardly ever use TeX nowadays, but when I do, I use pdf-tools. Auto Revert mode doesn’t play nice with pdfs open in Emacs, often trying to revert them before TeX finishes writing to them, which results in ugly flickering.
-1:-- Ignoring pdfs when auto-reverting files (Post Marcin Borkowski)--L0--C0--2026-05-25T19:25:17.000Z

TAONAW - Emacs and Org Mode: Journelly and OSM for Emacs are good together

I mentioned OSM for emacs briefly before, but I haven’t played with it much. That’s because the maps never showed up correctly in the buffer: the map tiles were not aligned correctly and some appeared blank.

As it turns out, someone else had this problem and also found the culprit: visual-line-mode. I have it turned on by default as the majority of my work in Emacs involves org-mode and I need my lines wrapped in the buffer. With visual-line-mode disabled, OSM works as expected, including zooming in and out. Good stuff.

Now that I fixed OSM, I was wondering about something else I wanted to do for a while: having Journelly’s latitude and longitude fed automatically to OSM in Emacs, so I can view the location on a map.

Journelly captures locations and weather information for each note and stores those under properties, like so:

PROPERTIES:
:LATITUDE: ##.##########
:LONGITUDE: ##.##########
:WEATHER_TEMPERATURE: 62.1°F
:WEATHER_CONDITION: Cloudy
:WEATHER_SYMBOL: cloud
:END:

The OSM function that calls for those is osm-goto.

So what we need is a simple function to feed the properties values directly:

(defun jtr-goto-from-properties ()
(interactive)
(let ((lat (org-entry-get (point) "LATITUDE"))
(lon (org-entry-get (point) "LONGITUDE")))
(if (and lat lon)
(osm-goto (string-to-number lat) (string-to-number lon) osm-default-zoom)
(message "No LATITUDE/LONGITUDE properties found on this entry"))))

This is an interactive function that I use when I’m standing on the header in Journelly I want to see on a map. It’s quick and works well. Now I can use my Journelly entries, which are already in org-mode, as a base for a post with a map tile inside Emacs. OSM doesn’t have a native function to export an image, but since I usually want to annotate the image anyway before I make a post out of it, a regular screen-capture app is a good solution, at least for now.

-1:-- Journelly and OSM for Emacs are good together (Post TAONAW - Emacs and Org Mode)--L0--C0--2026-05-25T17:55:54.000Z

Sacha Chua: 2026-05-25 Emacs news

I liked the before/after snippets in Looking closer at Claude Generated Lisp Code. (Spoiler: people write nicer code.)

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-25 Emacs news (Post Sacha Chua)--L0--C0--2026-05-25T16:45:39.000Z

Wai Hon: Refining Org-mode Deadlines

For a long time, I didn't use deadlines in Org-mode at all. However, over the past year (or perhaps even longer, though I forget exactly when), I have found myself relying on them more and more. Deadlines have quietly become the backbone of my day-to-day productivity.

A New Prioritization Hierarchy

In my earlier post on task management workflow, my day-to-day focus was heavily centered around scheduled dates and TODO states. Today, my prioritization hierarchy has fundamentally evolved to:

Deadline + Priority > Schedule > TODO States

  • Deadlines + Priorities represent my primary focus. Deadlines show what must be delivered and when, while priorities help determine which deadline to tackle first. Together, they serve as the main driver for my planning.
  • Scheduled dates are reserved for habits, recurring chores, or temporary "snoozing" (hiding tasks until they need to be revisited).
  • TODO States (like NEXT or PROG) act as a backlog of next actions. If my deadline and prioritized items are blocked or completed, I look here to see what to pick up next.

Default Org Agenda View

However, the default deadline behavior in Org-mode didn't really work for me. Out of the box, deadlines look identical to scheduled tasks, and the short warning window makes them hard to plan around.

Here is the default Org agenda view:

org-deadline-before.png

Customized Org Agenda View

To support this deadline-first workflow, here are two tricks I used to turn Org-mode deadlines into a powerful planning tool.

Here is the customized Org agenda view:

org-deadline-after.png

Trick 1: Visual Deadlines with Custom Leaders and Sorting

In the Org agenda view, distinguishing scheduled tasks from deadlines at a glance is surprisingly difficult. Because they share a similar layout and color palette, a looming deadline can easily get lost in a sea of routine scheduled chores.

To solve this, I customized the "leaders" (the prefix text shown in the agenda) by prepending a bright red circle emoji (🔮) to all deadline items. This makes them immediately pop out.

Also, sort deadeline at the very top lines by customizing the org-agenda-sorting-strategy to clearly separate "deadline" and "scheduled" items.

Here is the Elisp configuration I use:

;; Shorten the leaders to reserve spaces for the repeater.
(setq org-agenda-scheduled-leaders '("Sched" "S.%2dx"))
(setq org-agenda-deadline-leaders '("🔮 0d" "🔮%2dd" "🔮-%1dd"))

(defun my/org-agenda-repeater ()
  "The repeater shown in org-agenda-prefix for agenda."
  (let ((pom (org-get-at-bol 'org-marker)))
    (if (or (org-get-scheduled-time pom) (org-get-deadline-time pom))
        (format "%5s: " (or (org-get-repeat) ""))
      "------------")))

;; Add repeater and effort to the agenda prefixes.
(setq org-agenda-prefix-format
      '((agenda . " %i %-12:c%?-12t%s%(my/org-agenda-repeater)")))

;; Add deadline-up to agenda to separate schedule and deadline.
(setq org-agenda-sorting-strategy
      '((agenda deadline-up habit-down time-up priority-down category-keep)))

This is an extension of my previous post on distinguishing repeated tasks. By shortening the scheduled leaders, we free up horizontal space for the repeater interval. The addition of the 🔮 emoji ensures that any item with an active deadline immediately commands attention.

Trick 2: Expanding the Warning Window to a Month

By default, Org-mode starts warning you about a deadline 7 days in advance. While a week sounds reasonable, in practice, it is often too short.

When a deadline suddenly appears on your agenda with only 7 days to go, it can easily disrupt your cadence. Since 7 days technically translates to only 5 working days, you might already be fully committed to other urgent tasks. Instead of helping you plan, a short warning window simply induces stress.

To fix this, I increased the default warning period from a week to a month (35 days, or 5 weeks):

(setq org-deadline-warning-days 35)

With a 35-day warning window, upcoming major deadlines are visible on the agenda far in advance. This gives me ample time to adjust my weekly plan and budget resources before the deadline becomes urgent.

Of course, not every task warrants a month-long warning. For minor tasks, you can override the default warning period on a per-item basis. For instance, you can use the -3d syntax to only trigger a warning 3 days prior:

DEADLINE: <2026-06-19 Fri ++28d -3d>

Conclusion

I used to find schedules and deadlines somewhat overlapping in Org-mode. However, separating them into distinct roles, by using custom leaders for urgency and a longer warning window for planning, has made my agenda a lot easier to parse. It is a simple config tweak, but it has made my planning a bit smoother.

-1:-- Refining Org-mode Deadlines (Post Wai Hon)--L0--C0--2026-05-25T05:00:00.000Z

I wrote about Harper before, but I wanted to expand now that I have it working on Kubuntu with a couple of more options.

Harper is good in two scenarios for me: first, when I want something quick and I don’t feel like starting a browser with Grammarly in it, and second, when I write a personal email and the idea of my words going to some AI grammar bot somewhere makes my skin crawl. Otherwise, for my blog (which is public anyway) and work email (I don’t care about those) Grammarly is definitely better.

The issue with Linux is that the makers of Harper geared it toward macOS (Homebrew) and Arch Linux, among other things. It was made for programmers by programmers, and these guys don’t bother with Ubuntu-like distros. Fair, but up until recently it meant I had to jump through hoops.

The quick and easy route in Ubuntu distros (which is what Kubuntu is) is to use snap. I know, I know. I didn’t want to either, but since the Harper makers don’t bother with flatpak, the other option was to install a Rust environment, which is a big overkill just for an app inside Emacs I use like once a month or so or less. I don’t like snap and I don’t use it, but I made an exception here. (Edit: I actually decided to go ahead with Rust and Cargo, and explained what I did)

Now, that snap “shortcut” is by a guy who works with Ubuntu (I think) and maintains his own package for it, so it’s on the edge channel (not stable) and seems to be a lot behind (version .49 to be exact, and Harper is currently 2.2.1!) so if Harper is your choice of grammar check, and you use it daily, I’d suggest against what I’m doing below. I’d install as needed in that case, Rust and all.

With that disclaimer, let’s move on: sudo snap install harper --edge.

Now in Emacs, in Linux, we want to tell it where harper is:

    (when (eq system-type 'gnu/linux)
               (add-to-list 'exec-path "/snap/harper/current/bin"))

When tells it to add the snap path only when running Linux, since I have the same config for both macOS and Linux.

That’s all
 After that, I’ve added some of Harper’s flags, or linters. Here’s the whole code as I have it in my emacs org settings:

          (with-eval-after-load 'eglot
            (add-to-list 'eglot-server-programs
                         '(org-mode . ("harper-ls" "--stdio"))))
    
           (setq-default eglot-workspace-configuration
                      '(:harper-ls (:dialect "American" :linters (:LongSentences :json-false :AvoidCurses :json-false))))
    
    ;; Besides choosing American as the language, I also want to ignore long sentences (the main issue is that it hides other errors nested in those) and I also want harper not to tell me when it thinks something is offensive. The full list of these options is in https://writewithharper.com/docs/rules. It needs to be nested inside the :linters option.
    
           (when (eq system-type 'gnu/linux)
             (add-to-list 'exec-path "/snap/harper/current/bin"))
    
    ;; on a mac, Harper is installed via Homebrew - on Kubuntu, the best option is snap - the harper team does not do a package (flatpak) unfortunately, and I don't want to install Rust just for harper. So.. meh.  I did sudo 'snap install harper --edge' for this.
-1:--  (Post TAONAW - Emacs and Org Mode)--L0--C0--2026-05-24T15:09:50.000Z

Irreal: Fonts and Typesetters

John Gruber has a very interesting—at least for those of us who obsess about typography—post on the fonts used by the various federal courts of appeal. For those of you who don’t know, the courts are very strict about the written format of their decisions and of the briefs filed with them. Not only is there a fixed and rigid format, the font used is also specified. Failure to adhere to the standard is prima facie reason for rejecting the filing. That said, each district has it’s own standards and choice of font. Some of those are particularly ugly versions of Courier and others are beautiful fonts such as Century Schoolbook and Equity.

The Supreme Court—which used to insist on hot-metal typeset documents—uses Century Schoolbook. Take a look at Gruber’s post for the interesting details.

None of this would be Irreal fodder except for a thread on the TUHS mailing list about LaTeX versus Troff for typesetting. Some of the discussion involved the difference between the input languages but a surprising amount talked about fonts as if Troff was still being run on a C/
A/T typesetter with a single fixed font. In fact, both typesetters can use just about any font although it is true that the output from each does have a distinctive look.

I wrote two books for a major publisher and typeset them using Troff so at the time I could probably have been considered a Troff expert. Then I started using Lisp and partly as a result I moved to Emacs. Since then, I do all my writing in Org mode, which, of course, uses LaTeX for producing typeset output.

Sadly, these days I can’t be considered an expert in either Troff or LaTeX but it doesn’t really matter because Emacs has me covered. I simply write in Org mode and get great results for printed content. I still know enough LaTeX to tweak my results if I need to so I have the best of both worlds: the ease of Org and the power of LaTeX.

-1:-- Fonts and Typesetters (Post Irreal)--L0--C0--2026-05-24T14:43:57.000Z

James Endres Howell: Match Emacs and GNOME light/dark theme

Light or dark? GNOME side

I like both, depending on how much light is in the room. I much prefer to set my desktop light or dark manually than to automate with timers.

On GNOME light or dark is color-scheme and you can set read and set it from the command line. You can read it from the command line (default light theme is called default)

$ gsettings get org.gnome.desktop.interface color-scheme | tr -d "'"
default

and you can set it from the command line (default dark theme is called prefer-dark)

$ gsettings set org.gnome.desktop.interface color-scheme prefer-dark

will change it to dark.

(You can also set other preferred GNOME themes this way.)

Light or dark? Emacs side

Protesilaos has published a gazillion pretty themes, but I prefer his modus-themes for their visual simplicity and also for their UI amenities. For example you can set one light theme (modus-operandi family) and one dark theme (modus-vivendi family) and toggle between them:

(setopt modus-themes-to-toggle '(modus-operandi-tinted modus-vivendi-tinted))
(bind-key "C-c m" #'modus-themes-toggle)

And there is the custom-variable custom-enabled-themes, usually set in your custom-file, that determines what themes are initially enabled.

(setopt custom-enabled-themes '(modus-operandi-tinted modus-vivendi-tinted))

The order of this list determines which theme is activated by default: the first one.

Matching Emacs to GNOME

But when I start Emacs, I want the startup theme to match the GNOME theme! So I took custom-enabled-themes out of the custom file and added these lines to early-init.el:

(defconst jeh/modus-themes-list
  (let* ((light 'modus-operandi-tinted)
         (dark 'modus-vivendi-tinted)
         (gnome-theme
          (car (split-string
                (shell-command-to-string
                 "gsettings get org.gnome.desktop.interface color-scheme | tr -d \"'\"")))))
    (cond ((string= gnome-theme "default")
           `(,light ,dark))
          ((string= gnome-theme "prefer-dark")
           `(,dark ,light))))
  "List of modus themes IN ORDER: first element is the default theme,
which depends on whether the GNOME color-scheme is light or dark.")

(setopt custom-enabled-themes  jeh/modus-themes-list)
(setopt modus-themes-to-toggle jeh/modus-themes-list)

Toggling them together

I wish I could remember from whom I stole this little bash script to toggle GNOME theme. Note the last line I added, which also toggles Emacs theme.

#!/usr/bin/env bash
class=org.gnome.desktop.interface 
name=color-scheme
status=$(gsettings get "$class" "$name" | tr -d "'")
if [[ $status = "default" || $status = "prefer-light" ]]; then
    new_status="prefer-dark"
else
    new_status="default"
fi
gsettings set "$class" "$name" "$new_status"
emacsclient -e '(modus-themes-toggle)'

Save it to somewhere in your path (e.g. ~/bin/gnome-toggle-light-dark.sh) and chmod +x ~/bin/gnome-toggle-light-dark.sh. Test it from the command line.

The best part is that GNOME lets you bind a keyboard shortcut to a script:

Settings ⟶
    Keyboard ⟶
        View and Customize Shortcuts ⟶
            Custom Shortcuts ⟶
                + (add shortcut)
gnome-settings-screenshot-1.png
gnome-settings-screenshot-2.png
gnome-settings-screenshot-3.png

Now you can toggle GNOME and Emacs themes together as the sky determines your mood.

-1:-- Match Emacs and GNOME light/dark theme (Post James Endres Howell)--L0--C0--2026-05-23T19:23:00.000Z

Irreal: Giving RSI The Thumb

Emacs’ shortcuts and their role in RSI are a staple of Emacs commentary. Everyone, it seems, has their own methods for relieving stress on their hands as they use Emacs. Prot, for example, thinks that one-shot modifiers are the answer. Others recommend using a split keyboard or simply mapping Caps Lock to Ctrl.

A post over at meanwhiling has another suggestion: use your thumbs. That’s also familiar advice but the post goes into specific details. Those details, in a nutshell, are to map the two keys nearest to either side of the space bar to Ctrl and the two keys next to those to Meta.

That setup has the advantages that

  1. Both the Ctrl and Meta keys can be pressed with a thumb
  2. There is a Ctrl and Meta key on both sides of the keyboard so you never have to press the modifier and target key with the same hand.

The only remaining question is what to do about Hyper and Super. I use both of those, especially Hyper, all the time so I need them easily accessible. That’s made easier for me because I don’t mind using the same hand for the modifier and target keys. I still use Caps Lock for Ctrl and my thumbs for everything else. If my pinky ever starts complaining about Ctrl I’ll probably just swap Ctrl and Super. I’d do that anyway except for muscle memory and the fact that my hands don’t hurt.

I do think using your thumbs for your most used modifiers make sense and modern keyboards make that pretty easy to set up.

-1:-- Giving RSI The Thumb (Post Irreal)--L0--C0--2026-05-23T15:07:47.000Z

Emacs APAC: Announcing Emacs Asia-Pacific (APAC) virtual meetup, Saturday, May 23, 2026

This month’s Emacs Asia-Pacific (APAC) virtual meetup is scheduled for Saturday, May 23, 2026 with BigBlueButton and #emacs on Libera Chat IRC. The timing will be 1400 to 1500 IST.

The meetup might get extended by 30 minutes if there is any talk, this page will be updated accordingly.

If you would like to give a demo or talk (maximum 20 minutes) on GNU Emacs or any variant, please contact bhavin192 on Libera Chat with your talk details:

-1:-- Announcing Emacs Asia-Pacific (APAC) virtual meetup, Saturday, May 23, 2026 (Post Emacs APAC)--L0--C0--2026-05-23T06:53:58.000Z

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

Bicycle for Your Mind: BBEdit 16 Disappoints

IconIcon

Product: BBEdit 16
Price: $60 for new version, $30 for upgrade from version 15, $40 for upgrade from versions prior to that. Mac App Store version pricing is different.

BBEdit keeps to an upgrade schedule of about two and a half years between major versions. It is about that time and there is a new version of BBEdit. Version 16.

It is accompanied as usual by extensive release notes. This is the one product whose release notes I love reading. They are extensive and they are sometimes funny. The developers believe that it is important to document the changes to the program and they are serious about that. I wish more programs did that. It shows a care for their customers and their craft.

What Is New?

  • Expanded Shortcuts support. This is going to be useful to the heavy user of macOS Automations and BBEdit. I have not explored this much.
  • Search for text in images. Sure this is useful. But I have other tools to do this for me.
  • Color Customizations for Projects and Notebooks. I like this. I have a couple of projects and a couple of notebooks always open in BBEdit. Using different themes gives me a visual cue to identify them. Useful.
  • AI Chat Worksheets improvements. I am sure this is important to some people, I am not interested in this.

There are a whole host of other changes. One of them stuck out to me:

  • Support for vi keyboard emulation, for basic navigation and editing. There are a whole host of users who swear by vi keyboard commands. They are going to be ecstatic. I am ambivalent. I use Emacs keybindings. I also like the native BBEdit keybindings. I have been using this program for about twenty years.

A Tangent

BBEdit has a problem. It is a mature program with a feature-set which has been honed over a long time (since 1992). It has old-school roots. No bold, no italic. They take the concept of being a “text-editor” seriously. The product is not user-extendable in any meaningful way.

Yes. You can write an AppleScript, Text Factories, even themes (although for a product this old, there is a strange paucity of themes). But the base product is not user-extendable. It is not VSCode, Zed, Sublime Text, VIM, or Emacs. You will never see something like Org-mode written for BBEdit. It is not designed for that.

But it has a repeatable two and a half year upgrade cycle. What do you add? What do you highlight as the new great feature which will make existing users upgrade or new users adopt? How do you keep up with the Jones’s? Or in this case, the VSCode’s, and the Zed’s of the world?

What brought this tangent on? I looked at the vi implementation. Nowhere in the abundant documentation of the product does the developer provide a listing of the commands they support. Check out Zed’s documentation for VIM keybindings as a comparison. They are extensively documented and continuously improved. BBEdit is quiet about the details. Why? This is a feature which some customers have been asking for, for a long time. Actually when it comes to VIM keybindings, people who love them want them everywhere and they are a vocal bunch, so every editor launched has to face this clamor. BBEdit gives in to the demand, but somewhat reluctantly. “I am going to implement it, but I am going to keep quiet about the details.” Why?

To me, BBEdit is a program which is being dragged into the world of modern text editors, scratching and screaming. You want minimaps? How does this look to you?

minimapminimap

You want a command palette?

Command Palette?Command Palette?

The command palette lists commands and files. What? A file is not a command. I am sure that the developer knows that.

It is an attempt to replicate what the competition is doing but the implementation is half baked. The reasons might be technical limitations, or it might be lack of commitment, but the effect is underwhelming. VI keyboard implementation is another example of that.

BBEdit is by design not extendable. Which means no third-party extensions/packages. What the developer gives you is all you are going to get. This leaves it vulnerable to new editors like VSCode and Zed with their built in extensions support. It is also not competitive with old editors like VIM (neovim) or Emacs. Both of them have an extensive ecosystem of extensions and packages. The ecosystem around these competitors make BBEdit look ancient and more distressingly, restrictive.

I am obviously biased in this evaluation. I use Emacs. I am also not a developer. I am a writer. I write in Markdown and Org-mode. Markdown is better implemented in Emacs. BBEdit doesn’t do Org-mode. It is not close. They are different worlds. Org-mode can do things which BBEdit cannot dream of.

Maybe BBEdit should make a conscious decision to be what it is. A fantastic old-school text editor, which is secure, stable and efficient at slinging around text. Concentrate on the following areas where you have a competitive advantage:

  • macOS automation.
  • Supporting native macOS features. Versions, keyboard commands, Text Replacements, and the like.
  • Explore the concept of Notebooks more thoroughly. Linking between documents and sections within documents would be a great addition.

The two and a half year upgrade cycle? I have no answer for that.

Disorganized Thoughts

If you are an user who is new to text editors try out the free version of BBEdit. Look at VSCode and Zed as capable free alternatives.

If you are writing Markdown and that is what you are using a text editor for, iA Writer and MarkEdit are better. Their support for Markdown is better.

If you are interested in note-taking. Obsidian is better.

If you are an existing paid user, you know the product, make the best call for you. If you are using the free version, upgrade.

If you are interested in building a life around text files, Emacs is the better option. Remember that the learning curve is pretty steep in Emacs. BBEdit has a smoother learning curve, but for the esoteric features of BBEdit you need to read the manual. Thankfully that comes with the program and it is excellent.

Don’t be fooled by the rhetoric on “Mac-assed” application and how BBEdit embodies that. Firstly “Mac-assed” is a nebulous descriptor and I would argue that Zed is as “mac-assed” as BBEdit. Or iA Writer is more “mac-assed” than BBEdit. Think versions and text replacement support.

So who should buy BBEdit 16?

  • Existing users who love BBEdit.
  • Those looking for a stable, efficient text editor which comes with excellent support and extensive documentation.
  • Those looking for an editor which handles large files with no problems. BBEdit is good at that. They are not the only solution for that feature. Zed is good at that too. And Zed does that with excellent syntax highlighting.

Conclusion

BBEdit 16 is underwhelming. I like some of the additions but they are not crucial to me. Heavy users of BBEdit might have a different take on the nature of the update.

I think that BBEdit is near the end of its justified existence. This was my take on version 13: BBEdit 13: It Sucks a Little - Bicycle For Your Mind. On version 14: BBEdit 14 Protects You From “Untitled Text” Infestation - Bicycle For Your Mind. I was so underwhelmed by version 15, that I didn’t write about it.

Version 16 is not much different. It doesn’t introduce much by the way of new features and it doesn’t fix some of the glaring inconsistencies from previous versions (Commands can’t include files, that is just dumb, and has been this way since version 14).

I can recommend the free version of BBEdit.

The paid version? Not for the new user. Dependent on your needs there are better alternatives available to you. It is a good idea to explore them before you adopt BBEdit.

macosxguru at the gmail thingie.

Update:

Another take on BBEdit 16. BBEdit 16 Searches for Text in Images, Adds Shortcuts Actions, and More - TidBITS.

Another detailed, positive take on the new BBEdit 16. Michael Tsai - Blog - BBEdit 16.

-1:-- BBEdit 16 Disappoints (Post Bicycle for Your Mind)--L0--C0--2026-05-22T07:00:00.000Z

Vineet Naik: tagref can now be used with org-mode files

tagref screenshot

I recently contributed a patch to tagref that makes it play nicely with Emacs org-mode files. The PR has already been merged and the feature is available since version 1.12.0.

In this post I want to explain what the PR improves and show how tagref can be used in a project where internal/developer documentation in written in org-mode. But first, let me briefly introduce tagref.

What is tagref?

tagref is a command-line tool that helps manage "tags" and "references" in a project. The idea is based on cross-referencing code and documentation, inspired by the GHC notes system described in the Glasgow Haskell Compiler (§5.6) chapter of the AOSA book.

In short, you can annotate code (or text in any file) with a tag inside a comment:

1
2
3
4
5
// [tag:rare-edge-case]
function handleRareEdgeCase() {
  ...
  ...
}

The tag can then be referenced elsewhere in the repository, such as a doc that explains why the particular edge case might happen or what the developer specifically needs to consider before changing that code.

1
2
3
### A rare edge case

[ref:rare-edge-case]

The same tag can be referenced in other files too. This way, different parts of code and docs become interconnected. When a developer comes across a ref they can quickly look up the tag, the associated notes as well as other references to get a holistic understanding of the code they are about to touch.

The tags and refs can be managed through a command-line interface provided by tagref to,

  • list all tags and refs
  • check that the referenced tags actually exist and that there are no duplicate tags
  • list all unused tags

The check command can be run in a pre-commit hook or CI pipeline. This helps catch drift between code and docs, which is quite likely when internal documentation (architectural decision records, how-to guides, troubleshooting guides, checklists etc.) lives separately from the code.

Inside a monorepo (such as captrice's codebase), this kind of documentation and note-taking convention, along with the tagref tool, provides a decent system for annotating a source of truth (usually code, but sometimes a doc), and pointing back to it from other places in the repo. Markdown is probably the more popular format for such docs but I prefer to use org-mode, at least in my personal projects.

What did my PR solve?

Besides user defined tags, tagref also supports refs pointing to files and directories in the repository.

1
2
3
4
5
6
7
// Refer: [file:dev-docs/weekly-stats.org]
export async function computeWeeklyStats(
  db: IdbModel,
  now?: Date
): Promise<WeeklyStats> {
 ...
}

The above example is taken from captrice's codebase. The dev-docs/weekly-stats.org file documents optimizations and other decisions about calculating and displaying weekly stats on the home page.

The default sigil for file references is file: which happens to be exactly the same as the bracket-link syntax that org-mode uses for internal links. In org-mode, an internal link to another document can be added as,

1
2
* User home page components
  - [[file:./weekly-stats.org][Weekly stats]]

However, org-mode expects the file path to be relative to the current file, whereas tagref (prior to version 1.12.0) considers all paths to be relative to the working directory. I'd been working around this by specifying doc: as the custom file sigil, but there were limitations:

  1. The --file-sigil option had to be explicitly specified every time tagref was run, otherwise the check would fail.

  2. Despite having cross referencing between org files, tagref's check command couldn't be leveraged to catch broken links.

PR #273 addresses this by adding optional support for relative paths in file and directory references. If the path is prefixed with special path components such as ./, ../ and so on, it's considered relative to the file that contains the reference. Otherwise it's considered relative to the working directory (same as the original behavior, which makes the change fully backward compatible).

For example,

  • [file:./weekly-stats.org] will be considered relative to the file in which it exists

  • [file:weekly-stats.org] will be considered relative to the working directory

Preventing Emacs from normalizing relative paths

When editing org-mode files in Emacs, one almost never types out bracket links by hand. Instead, C-c C-l or M-x org-insert-link is used to insert a link interactively. But then the file path gets normalized i.e. even if ./doc.org is explicitly specified, it gets replaced with doc.org which is shorter and simpler representation of the same path.

This would cause tagref to treat it relative to the working directory. To prevent this, we can tell emacs to skip normalization of relative file paths. However, the solution feels inelegant as we're effectively patching a natively compiled core function file-relative-name in emacs, and not just an org-mode specific function. Considering this, we can conservatively define the advice such that it affects only those org buffers where the org-link-file-path-type variable is set to 'relative as a local binding.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  ;; @HACK: When file-based link is added in an org file using the
  ;; bracket link syntax, we want a relative path in the same
  ;; directory to contain a `./' prefix if `org-link-file-path-type'
  ;; is set to `'relative'. This makes it work well with the `tagref'
  ;; tool. Without this advice, the path gets normalized
  ;; e.g. `./doc.md' becomes `doc.md' even when the former is
  ;; explicitly specified.
  ;;
  ;; This feels a bit hacky though because `file-relative-name' is a
  ;; core emacs function that we're patching and not an org-specific
  ;; one. Hence we're checking multiple pre-conditions to ensure that
  ;; the behavior takes effect only when required and can also be
  ;; opted out of.
  (advice-add 'file-relative-name
              :filter-return
              (lambda (path)
                (if (and (derived-mode-p 'org-mode)
                         ;; Only if set locally (e.g., .dir-locals.el)
                         (local-variable-p 'org-link-file-path-type)
                         (eq org-link-file-path-type 'relative)
                         (not (file-name-absolute-p path))
                         (not (string-prefix-p "." path)))
                    (concat "./" path)
                  path)))

To opt into this behavior, you need to override org-link-file-path-type locally for all files in the project. This can be conveniently done through a .dir-locals.el file at the repository root.

1
2
3
(
 (org-mode . ((org-link-file-path-type . relative)))
)

With these two pieces in place, tagref works seamlessly with org-mode files.

-1:-- tagref can now be used with org-mode files (Post Vineet Naik)--L0--C0--2026-05-21T18:30:00.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

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

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

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!