Rediscovering org-clone-subtree-with-time-shift: if you have regular meetings, this is the function for you.

Create a Meeting event with everything you need (Zoom links, place for notes, tags, etc) and clone it X number of times. Emacs will ask you for the frequency. You now have X meetings ready.

-1:--  (Post TAONAW - Emacs and Org Mode)--L0--C0--2025-11-17T15:43:34.000Z

Protesilaos Stavrou: Emacs: new Doric themes ‘doric-siren’ and ‘doric-mermaid’

I am developing two new themes for my minimalistic doric-themes package for Emacs. These combine marine hues with some warmer accents, cast on a fairly prominent backdrop. doric-siren is a light theme, while doric-mermaid is dark. Below are some screenshots to give you an idea of what to expect.

[ Or just check all the pictures: https://protesilaos.com/emacs/doric-themes-pictures. ]

doric-siren

doric-siren theme sample

doric-siren theme sample

doric-siren theme sample

doric-siren theme sample

doric-mermaid

doric-mermaid theme sample

doric-mermaid theme sample

doric-mermaid theme sample

doric-mermaid theme sample

Coming in doric-themes version 0.5.0

The character of the themes is established and, in principle, I will not change them further. Though I am giving it a few more days of further testing to confirm I did not miss something. Expect these and other improvements to be available in the next stable version of the doric-themes, which I expect to publish before the end of November.

About the Doric themes

The Doric themes use few colours and will appear monochromatic in many contexts. They are my most minimalist themes. Styles involve the careful use of typographic features and subtleties in colour gradients to establish a consistent rhythm. Legibility is still high.

If you want maximalist themes in terms of colour, check my ef-themes package. For something in-between, which I would consider the best “default theme” for a text editor, opt for my modus-themes.

-1:-- Emacs: new Doric themes ‘doric-siren’ and ‘doric-mermaid’ (Post Protesilaos Stavrou)--L0--C0--2025-11-17T00:00:00.000Z

Jack Baty: I think I prefer using Linux, but can I abandon macOS?

Some thoughts and observations around my feelings about using Linux vs macOS.

For the past week or so, I’ve been switching between Linux and macOS several times a day. I’ve been working towared full-time Linux for nearly a month, and planned to relegate the Mac to photo processing only. A sort of photo appliance. While doing that, though, I opened some of my favorite Mac-only apps, and immediately doubted the entire Linux experiment. Things would be much simpler if I used macOS for everything. Right?

I’ve spent decades with tools like Tinderbox and DEVONthink and BBEdit. It would be hard for me to give them up.

But something unexpected happened during all this. Switching to the Mac began to feel like a step backwards, experience-wise. (I told you it was unexpected). The Mac felt cumbersome. I felt as if I was spending most of my time on macOS moving and resizing windows. I’d end up with like 35 overlapping Finder windows for some reason. It felt chaotic, compared to the tidy window management of Hyprland.

I tried using AeroSpace on the Mac for a couple days, but it wasn’t the same as Hyprland. There are other apps that try to emulate tiling, but none that I’ve tried felt satisfactory.

The other unexpected thing is that I’m starting to prefer certain Linux key bindings. With Caps Lock mapped to Control, Ctrl-c and Ctrl-v are actually easier to hit on my keyboard than Command-c and Command-v. I do miss the Emacs-bindings-everywhere on macOS, but what if I spend more time with Vim bindings wherever possible? Will I miss the other bindings as much?

I’m beginning to understand, and possibly even prefer, the Linux environment, but software is a different story.

Photo editing in Darktable is getting easier for me, but it’s got nothing on the speed and ease of using Lightroom Classic or Capture One. This is why I planned to keep the Mac around, just for scanning and processing photos.

Another factor is that while many of my favorite Mac apps aren’t available on Linux, nearly all of the Linux apps I’m interested in are available for macOS. It would seem like using a Mac would be a no-brainer, then. Except I can’t kick the feeling that Linux suits me, somehow. Or at least it could, with a bit more experience.

I’m finding that I like how it feels to be using Linux1. It feels good knowing that it’s all mine to do with as I please on whatever hardware I want. I like not thinking about whether Apple will course-correct any time soon.

So, where does that leave things? I’m not sure. If I’m to continue toward my goal of reducing & simplifying, running two operating systems is a bad idea, so I would like to pick one and stick with it. Knowing me, I’m not sure that’s feasible.

One indication is that I switched to Linux in order to write this post, and it felt like a relief after being on macOS most of the day. That tells me something. Onward!

  1. Unfortunately, Omarchy comes with some uncomfortable baggage that I’m choosing to live with, for now. No need to scold me.

✍️ Reply by email
-1:-- I think I prefer using Linux, but can I abandon macOS? (Post Jack Baty)--L0--C0--2025-11-16T20:55:18.000Z

Irreal: JTR On Projects In Emacs

JTR over at The Art Of Not Asking Why has a post discussing his current scheme for handling projects in Emacs. It’s a post that discusses the problem that many of have with integrating our Org files across all our devices. JTR, like me, lives in the Apple ecosystem and needs a way of interacting with his Org files from his iPhone and iPad. The situation isn’t any better in the Android world.

For various reasons, JTR has stopped using iCloud for his syncing. I’m sympathetic to his complaints but doubt that any other solution would be an improvement. Servers go down and there are network problems. This happens regardless of what cloud solution you’re using. If you’re fortunate to work from home, you can, of course, arrange to do everything locally, which avoids many of the cloud problems.

Given these realities, JTR has settled on some procedures to ease his workflow. Oddly, most of them don’t involve the networking aspects of his workflow. Rather, he restructured how he arranges his Org files and made all his workflows project oriented. You can read the details in his post and judge whether or not they’ll work for you.

The takeaway is that trying to spread access to your Org files—or more generally, your Emacs files—across all your devices is a difficult problem for which there isn’t a compelling solution. Beorg or Plain Org are nice apps that can help in the Apple domain and there are others for Android but they’re not the same as being in Emacs. In the end, you may have to adjust your Emacs use in some way as JTR did.

-1:-- JTR On Projects In Emacs (Post Irreal)--L0--C0--2025-11-16T15:46:45.000Z

Bozhidar Batsov: Burst-driven Development: My Approach to OSS Projects Maintenance

I’ve been working on OSS projects for almost 15 years now. Things are simple in the beginning - you’ve got a single project, no users to worry about and all the time and the focus in world. Things changed quite a bit for me over the years and today I’m the maintainer of a couple of dozen OSS projects in the realms of Emacs, Clojure and Ruby mostly.

People often ask me how I manage to work on so many projects, besides having a day job, that obviously takes up most of my time. My recipe is quite simple and I refer to it as “burst-driven development”. Long ago I’ve realized that it’s totally unsustainable for me to work effectively in parallel on several quite different projects. That’s why I normally keep a closer eye on my bigger projects (e.g. RuboCop, CIDER, Projectile and nREPL), where I try to respond quickly to tickets and PRs, while I typically do (focused) development only on 1-2 projects at a time.

There are often (long) periods when I barely check a project, only to suddenly decide to revisit it and hack vigorously on it for several days or weeks. I guess that’s not ideal for the end users, as some of them might feel that I “undermaintain” some (smaller) projects much of the time, but this approach has worked for me very well for quite a while.

The time I’ve spent develop OSS projects has taught me that:

  • few problems require some immediate action
  • you can’t always have good ideas for how to improve a project
  • sometimes a project is simply mostly done and that’s OK
  • less is more
  • “hammock time” is important

To illustrate all of the above with some example, let me tell you a bit about copilot.el 0.3. I became the primary maintainer of copilot.el about 9 months ago. Initially there were many things about the project that were frustrating to me that I wanted to fix and improve. After a month of relatively focused work I had mostly achieved my initial goals and I’ve put the project on the backburner for a while, although I kept reviewing PRs and thinking about it in the background. Today I remembered I hadn’t done a release there in quite a while and copilot.el 0.3 was born. Tomorrow I might remember about some features in Projectile that have been in the back of my mind for ages and finally implement them. Or not. I don’t have any planned order in which I revisit my projects - I just go wherever my inspiration (or current problems related the projects) take me.

And that’s a wrap. Nothing novel here, but I hope some of you will find it useful to know how do I approach the topic of multi-project maintenance overall. The “job” of the maintainers is sometimes fun, sometimes tiresome and boring, and occasionally it’s quite frustrating. That’s why it’s essential to have a game plan for dealing with it that doesn’t take a heavy toll on you and make you eventually hate the projects that you lovingly developed in the past. Keep hacking!

-1:-- Burst-driven Development: My Approach to OSS Projects Maintenance (Post Bozhidar Batsov)--L0--C0--2025-11-16T12:16:00.000Z

TAONAW - Emacs and Org Mode: Handling project in Emacs - the 2025 version

Ever since I’ve decided to move away from iCloud1, I’ve had a hard time syncing my org files with Beorg, which is how I worked with org-mode tasks on my iPhone. Frustrated, I looked into a solution that I should have revisited long ago: Plain Org.

I got Plain Org before I heard of Journelly, so it’s not just because I’m a fan of Álvaro’s work. At the time, I was just looking for an app that could read org files and lay out my projects in a nice, clear way. As it turns out, Plain Org does more than that - by doing less.

Compared to Beorg, Plain Org is very minimal. But it works with Synctrain (Syncthing for iOS), it accesses my org files on my iPhone quickly and easily, and it lets me make quick modifications when needed. For everything else, there’s Emacs. And that’s what I seem to have forgotten.

It took me a while to reconnect with the understanding that my iPhone is not the place to manage tasks and projects, despite what everyone around me seems to think, whether it’s my workplace with its Microsoft Office suite or Apple with its ever-improving Notes and Reminders. As I mentioned earlier, other apps look and work great, as long as you play by their rules. As soon as you need something customized for your needs, you’re out of luck. I can play by the rules to an extent, but not when it comes to how I think and work. I guess I had to write it out here to arrive at that conclusion again, and surprise surprise, things are working out again.

What followed was reorganizing all my org files. A deep system cleaning that was much overdue. First, I archived many of them in my archive folder. Next, I went into my projects org file itself and archived a big chunk of projects that should have been completed and/or put away a long time ago. The trick was to remind myself that archiving is not the same as throwing away something: it’s simply putting it out of sight. It’s a simple rule: if it just sits there staring me in the face for more than a week, it needs to be archived. If I need to work on it again, I can put it back: org-refile is a powerful tool. I can always go into my archive folder, which is not a part of my agenda on purpose, and search through it with occur or consult-grep.

Speaking of my org-agenda: I got rid of scheduled TODO tasks, and I’m trying to keep it this way.

The kind of work I do today is 100% projects. There’s no such thing as a simple task; if it’s simple, it gets delegated. This means each project header, which is signified by the keyword ACTIVE, has somewhere between 5 to 20 subheaders: meetings, additional tickets, purchases, notes, emails, documents attached with org-attach, you name it.

Making these subheaders into scheduled TODO items quickly overwhelms my agenda and hurts motivation. Besides, I was stuck in the habit of always having a next-action item for every single thing, so many of those TODOs just ended up being something like “Follow Up” or “Reminder.” That’s a waste. A project is already marked with “ACTIVE” for a reason, after all. I know I need to follow up on something, that’s the entire point. The other thing is that the project header (the parent header) should be the header I work with. It’s where I keep my logbook notes (C-c C-z), and where I clock in and out. I used to do this for each subtask, but then I had to think about which notes go under which task, and it made it harder to follow up later, as I had to search across different tasks containing different fragments of notes. It’s too much running in circles. Now I just look at my list of projects, pick one to work on, and start a clock (C-c C-x C-i). When I’m done, I clock out (C-c C-x C-i) and write a few notes about what I did.

I still use subheaders when I need to save something (like an email, a ticket, or meeting notes), or when I work on something that takes more than half an hour on its own.

My work environment is a hectic mess these days, and Emacs is the only thing that is flexible enough (as always) to deal with… everything. The amount of productivity and communication apps people at work around me use is staggering, but they all work in the browser, need to be online, and don’t allow to customize things.

I need to be able to organize my head in Emacs. This is so important that I’m considering enforcing a small unofficial “break” during the day when I just sit down and clean up my projects and actually do some stuff. Otherwise I’ll be stuck all day just running after emails.

Footnotes

1 Many folks use iCloud and are happy with it, so why do I make my life difficult? The two technical reasons are my Linux desktop, which I use to access some of my org files, and my Android, which is more like a backup device to capture some notes. Another reason is the lack of control of iCloud: it works most of the time, but when it doesn’t, it really messed me up. It just stays stuck and doesn’t sync for whatever reason, and in case of a conflict, iCloud “decides” which file is the right one and overwrites whatever was there before. When I lost some work because of this recently, it was the last straw. Syncthing would always create a conflict file, where I can run Diff in emacs and quickly decide what I want to keep. It also has a built-in file versioning in its folders, which has saved me a couple of times in the past.

There’s also the tinfoil hat: I’m grumpy guy who yells at clouds. To put simply, I don’t trust Apple to store my personal and private files. After viewing their transperency report I was surprised to find out they share data with law enforcement 70-80 percent of the time. I just don’t like the “think of the kids” PG approach.

-1:-- Handling project in Emacs - the 2025 version (Post TAONAW - Emacs and Org Mode)--L0--C0--2025-11-15T03:10:11.000Z

Rahul Juliato: Crafting Your Own Snippets with Emacs Built-In Abbrev Mode

In the world of text editing and programming, templating is a superpower. It saves keystrokes, reduces errors, and lets you focus on the bigger picture. For Emacs users, battle-tested packages like yasnippet and tempel are often the go-to solutions, offering powerful features and extensive libraries.

But what if you're in the mood for a little crafting? What if you want a solution that's built right into Emacs, requires no third-party installations, and can be easily copied and pasted into any configuration?

The all mighty built-in abbrev-mode is there for all of us Emacs users! In this post, we'll explore how you can leverage this humble, built-in minor mode to create a powerful, progressive, and deeply personal (for good or bad) snippet system.

What is Abbrev Mode?

At its core, abbrev-mode is a simple expansion system. You define an "abbreviation" (a short string) and an "expansion" (the text it should be replaced with). When the mode is active, it can automatically replace the abbrev with its expansion as you type.

However, I prefer a more deliberate approach. Instead of having abbrevs expand automatically, I like to trigger them manually with the command expand-abbrev, which is bound to C-x '. This gives me full control and avoids unintentional expansions. If you prefer the automatic method, you can always enable it with M-x abbrev-mode.

Level 1: Simple Text Replacements

Let's start with the basics. The simplest use of abbrevs is to replace a short string with a longer one. This is perfect for things you type often, like symbols, emojis, or special characters.

Here is a minimal configuration example (full nicer code on the end of this post):

(use-package abbrev
  :ensure nil
  :custom
  (save-abbrevs nil)
  :config
  (define-abbrev-table 'global-abbrev-table
	'(;; Arrows
	  ("ra" "→")
	  ("la" "←")
	  ("ua" "↑")
	  ("da" "↓")

	  ;; Emojis for context markers
	  ("todo"  "👷 TODO:")
	  ("fixme" "🔥 FIXME:")
	  ("note"  "📎 NOTE:")
	  ("hack"  "👾 HACK:")
	  ("smile"  "😄")
	  ("party" "🎉")
	  ("up"  "☝️")
	  ("applause" "👏")
	  ("manyapplauses" "👏👏👏👏👏👏👏👏")
	  ("heart" "❤️")

	  ;; NerdFonts
	  ("nerdfolder" " ")
	  ("nerdgit" "")
	  ("nerdemacs" ""))))

With these defined, I can type ra and then C-x ' to get a , or fixme followed by C-x ' to get "🔥 FIXME:". It's simple, fast, and incredibly useful.

abbrev-mode-01

Level 2: Running Functions

What if you need more than just static text? What if you want to position the cursor in a specific spot after the expansion? Abbrevs can do that too, by executing an Emacs Lisp function as part of the expansion.

Let's look at a common use case: creating a Markdown code block and placing the cursor inside it.

;; Markdown
("cb" "```@\n\n```"
 (lambda () (search-backward "@") (delete-char 1)))

;; ORG
("ocb" "#+BEGIN_SRC @\n\n#+END_SRC"
 (lambda () (search-backward "@") (delete-char 1)))

When I expand cb, it first inserts the string ˋˋˋ @\n\n\ˋˋˋ . Then, it immediately runs the provided lambda function, which searches backward for the temporary @ marker, deletes it, and leaves the point (the cursor) right where I need it, ready to type. Or mabe we want to do the same for org-mode? No problem, just check ocb.

abbrev-mode-02

You could also make variations of these examples by adding your most used language to the template, maybe adding comments, and whathever else you need!

Level 3: The Big Guns - Interactive Templates

Now for the really powerful stuff. Simple text replacement is great, and cursor positioning is even better, but what about true, interactive templates with placeholders? With a simple helper function (check for emacs-solo/abbrev--replace-placeholders on the full code on the bottom of this post), we can make abbrev-mode do just that.

The core of this system is a function that searches for placeholders like ###1###, ###2###, and a special cursor marker ###@###. It prompts you in the minibuffer for the value of each placeholder and, at the end, places the cursor exactly where you told it to.

Here are a few examples that use this function:

;; part of the `global-abbrev-table'
;;
;; JS/TS snippets
("imp" "import { ###1### } from '###2###';"
 emacs-solo/abbrev--replace-placeholders)
("fn" "function ###1### () {\n ###@### ;\n};"
 emacs-solo/abbrev--replace-placeholders)
("clog" "console.log(\">>> LOG:\", {###@### })"
 emacs-solo/abbrev--replace-placeholders)
("cwarn" "console.warn(\">>> WARN:\", {###@### })"
 emacs-solo/abbrev--replace-placeholders)
("cerr" "console.error(\">>> ERR:\", {###@### })"
 emacs-solo/abbrev--replace-placeholders)

When I expand rfc with C-x ', Emacs first asks me for the value of ###1### (the component name). Then it asks for ###2### (the initial content). It replaces the placeholders with my input and creates the full component structure in seconds.

abbrev-mode-03

The Complete Configuration

As promised, here is the full use-package declaration that powers this system. You can copy and paste this directly into your Emacs configuration to get started.

(use-package abbrev
  :ensure nil
  :custom
  (save-abbrevs nil)
  :config
  (defun emacs-solo/abbrev--replace-placeholders ()
	"Replace placeholders ###1###, ###2###, ... with minibuffer input.
If ###@### is found, remove it and place point there at the end."
	(let ((cursor-pos nil))
	  (save-excursion
		(goto-char (point-min))
		(let ((loop 0)
			  (values (make-hash-table :test 'equal)))
		  (while (re-search-forward "###\\([0-9]+\\|@\\)###" nil t)
			(setq loop (1+ loop))
			(let* ((index (match-string 1))
				   (start (match-beginning 0))
				   (end (match-end 0)))
			  (cond
			   ((string= index "@")
				(setq cursor-pos start)
				(delete-region start end))
			   (t
				(let* ((key (format "###%s###" index))
					   (val (or (gethash key values)
								(let ((input (read-string (format "Value for %s: " key))))
								  (puthash key input values)
								  input))))
				  (goto-char start)
				  (delete-region start end)
				  (insert val)
				  (goto-char (+ start (length val))))))))))
	  (when cursor-pos
		(goto-char cursor-pos))))

  (define-abbrev-table 'global-abbrev-table
	'(;; Arrows
	  ("ra" "→")
	  ("la" "←")
	  ("ua" "↑")
	  ("da" "↓")

	  ;; Emojis for context markers
	  ("todo"  "👷 TODO:")
	  ("fixme" "🔥 FIXME:")
	  ("note"  "📎 NOTE:")
	  ("hack"  "👾 HACK:")
	  ("pinch"  "🤌")
	  ("smile"  "😄")
	  ("party" "🎉")
	  ("up"  "☝️")
	  ("applause" "👏")
	  ("manyapplauses" "👏👏👏👏👏👏👏👏")
	  ("heart" "❤️")

	  ;; NerdFonts
	  ("nerdfolder" " ")
	  ("nerdgit" "")
	  ("nerdemacs" "")

	  ;; HTML entities
	  ("nb" " ")
	  ("lt" "<")
	  ("gt" ">")

	  ;; Markdown
	  ("cb" "```@\n\n```"
	   (lambda () (search-backward "@") (delete-char 1)))

	  ;; ORG
	  ("ocb" "#+BEGIN_SRC @\n\n#+END_SRC"
	   (lambda () (search-backward "@") (delete-char 1)))
	  ("oheader" "#+TITLE: ###1###\n#+AUTHOR: ###2###\n#+EMAIL: ###3###\n#+OPTIONS: toc:nil\n"
	   emacs-solo/abbrev--replace-placeholders)

	  ;; JS/TS snippets
	  ("imp" "import { ###1### } from '###2###';"
	   emacs-solo/abbrev--replace-placeholders)
	  ("fn" "function ###1### () {\n ###@### ;\n};"
	   emacs-solo/abbrev--replace-placeholders)
	  ("clog" "console.log(\">>> LOG:\", { ###@### })"
	   emacs-solo/abbrev--replace-placeholders)
	  ("cwarn" "console.warn(\">>> WARN:\", { ###@### })"
	   emacs-solo/abbrev--replace-placeholders)
	  ("cerr" "console.error(\">>> ERR:\", { ###@### })"
	   emacs-solo/abbrev--replace-placeholders)
	  ("afn" "async function() {\n  \n}"
	   (lambda () (search-backward "}") (forward-line -1) (end-of-line)))
	  ("ife" "(function() {\n  \n})();"
	   (lambda () (search-backward ")();") (forward-line -1) (end-of-line)))
	  ("esdeps" "// eslint-disable-next-line react-hooks/exhaustive-deps"
	   (lambda () (search-backward ")();") (forward-line -1) (end-of-line)))
	  ("eshooks" "// eslint-disable-next-line react-hooks/rules-of-hooks"
	   (lambda () (search-backward ")();") (forward-line -1) (end-of-line)))

	  ;; React/JSX
	  ("rfc" "const ###1### = () => {\n  return (\n    <div>###2###</div>\n  );\n};"
	   emacs-solo/abbrev--replace-placeholders))))

Conclusion

abbrev-mode may not be the flashiest tool in the Emacs ecosystem, but it has something special: it’s yours to shape. With just a handful of lines of Elisp, you can transform it from a humble text expander into a personal snippet engine that’s fast, predictable, and tailored to the way you think and write.

By starting small, simple replacements and handy symbols and gradually layering in cursor control, minibuffer-driven placeholders, and dynamic templates, you build a system that grows with your workflow. No external dependencies, no syncing snippet collections across machines, no black-box magic. Just pure Emacs, bending to your will.

Whether you stick with this approach or eventually reach for heavier tools like yasnippet or tempel, I hope this post shows that sometimes the most powerful solutions are the ones hiding in plain sight. And with a little crafting, abbrev-mode can become one of the most quietly transformative parts of your everyday editing.

Happy hacking. And happy expanding!

-1:-- Crafting Your Own Snippets with Emacs Built-In Abbrev Mode (Post Rahul Juliato)--L0--C0--2025-11-14T20:44:55.000Z

Jack Baty: A blog post written with NeoVim

It’s been the kind of day where using (or trying to use) Emacs frustrates me.

I’ve spent the past few weeks adapting my custom Emacs configuration to work on Linux. I was so confident that I would be moving to Linux that I ignored anything that might not work cross-platform. I should know better.

Today I was using my Mac and fired up Emacs and of course nothing worked. I spent nearly 2 hours futzing with it and I still don’t know what’s gone wrong. Reviewing Git commits hasn’t narrowed it down, either. It’s not the fact that I broke Emacs, it’s more that I’m so capable of breaking Emacs at any time. I do it more than I care to. I’m not in the mood, ya know?

My mood today has been less than festive, so my problems with Emacs just made a bad thing worse, so I quit Emacs in a huff.

I installed the MiniMax configuration for NeoVim and I am typing this post using it. I didn’t write a line of configuration and I didn’t tweak a thing. It’s working fine, for now.

MiniMax isn’t as fancy as LazyVim, but it’s also not as seizure-inducing by default. It strikes a nice balance between friendly and frenzied.

It’s not like I’m switching permanently back to Vim, but when I’m mad at Emacs, this NeoVim setup is pretty nice. Sometimes Emacs and I get into a destructive relationship, and we take a little break. That’s probably all this is.

✍️ Reply by email
-1:-- A blog post written with NeoVim (Post Jack Baty)--L0--C0--2025-11-14T19:05:34.000Z

Charles Choi: Thoughts on Funding Free Software Development

“I have always depended on the kindness of strangers.” — Blanche Dubois from “A Streetcar Named Desire”, Tennessee Williams.

DISCLAIMER: None of this post should be considered as financial or career advice of any kind. All views and opinions expressed here belong solely to Charles Y. Choi.

Not getting paid for making free software has long been recognized as a conundrum in the early 21st century, where much of its discourse is trenchantly summarized by the xkcd drawing “Dependency” [1] shown below.

For some time I’ve been gathering my thoughts on this matter, with stances that I’ll share in this post today.

Fundamentals on Bringing a Product to Market

Before talking about software, let’s review the basic steps needed to bring a physical product to market.

  1. Design & Development

    In this step, the intellectual construction of the product is defined.

  2. Manufacture

    In this step the product is mass produced. This step must occur after step 1.

  3. Distribution

    In this step the manufactured product is delivered. This step must occur after step 2.

  4. Marketing

    In this step, awareness of the product to its target market is raised to induce demand for it. Ideally this step is taken when there is high confidence in delivering the product to the market.

  5. Support

    In this step, the producers provide support for the product after it has shipped. This step must occur after step 3.

For a physical product, each step has a monetary cost associated with it. If the producer wishes to make a profit by selling the product, the price of the product must be greater than the cost to produce it. This leads to the incentive to manufacture and distribute as many copies as possible to maximize profit. At scale, the dominant costs are manufacturing and distribution for a physical product.

Software is Different

If the product is software using internet distribution, then its costs for manufacture and distribution become effectively zero. For a software provider, the dominant costs to bring a product to market are design & development, marketing, and support. Such costs are largely fixed with respect to demand. Since software has no intrinsic manufacturing nor distribution cost, for-profit software must resort to creating artificial scarcity to justify (and protect) profit that scales with meeting demand. Tactics to create scarcity include:

  • Constraining code to be closed-source.
  • Distributing only executables, typically code-signed to a model of computer.
  • Compilation-enforced licensing, typically tied to a subscription model.

What about Free Software?

With that background in place, let’s talk about free (both in speech and beer) software. In this post, I make no distinction between free (libre) and open source licensed software [2] as their differences fixate on the user’s ability to modify and redistribute received software. In contrast, this post views free software through the lens of the costs required to deliver said software to the market as described above.

Free software requires that its distribution be zero-cost to users. In contrast with for-profit software, free software evades the creation of artificial scarcity. In light of this, what options are available for developers who want to get paid for making free software? Here are three:

  1. Ask users to voluntarily give money after the software has been produced.
  2. Attach the developed software to a service or hardware-based business model.
  3. Get money upfront from users (or organizations) who have an interest in realizing some specific software, before its design and development are completed.

The first option offers providers no financial incentive to make free software, nor offers a reliable path to cover the cost to make it.

The second option relies on indirect compensation where the service or hardware revenue is expected to cover the cost of software development. Scarcity is imposed by restricting access to the service or hardware based on payment. This option is often taken by startups funded with venture capital.

The third option offers direct financial incentive for the developer to create free software, as money is taken by the developer with the expectation that said software is delivered at a future date. With this option, the design & development step is what is considered scarce. Upfront funding can come in a variety of forms, but largely fall into the following patterns:

  1. Institutional funding, where an organization puts up the funding.
  2. Angel funding, where a small group (< 5) of people contribute the funding.
  3. Crowdfunding, where a pool of small contributions from individuals (> 1,000) is gathered, typically with a target funding goal.

Which approach is taken can vary widely depending on the functionality of the software and the relationship (or lack thereof) between the developer and their benefactors. Note that getting money upfront to develop software precludes gaining profit from it based on demand after it is made, as free software insists its distribution be zero-cost to users. The only avenue for developer profit in this case is to demand funding that exceeds the baseline cost of producing the software.

Getting money upfront implies negotiation, which gives the developer agency to choose whether to commit to building the desired software. It also significantly raises risk to all involved parties if the software fails to be built.

Upfront funding aligns the incentives for producers and consumers of software by having agreement on a future deliverable:

  • Consumers pay to get the future software deliverable.
  • Producers work to build the future software deliverable.

While the exact number is unknown, I think a safe presumption is that single developers have built the vast majority of free software packages as evidenced by the Linux, Emacs, Python, and Node ecosystems. Most all of them resort to appeals to user gratuity, which is not enough to actually cover the market cost of designing & developing that software.

Given the above options for upfront funding, I’ll further make the assumption that most single developers do not have access to institutional nor angel funding. So, let's talk about crowdfunding.

Crowdfunding

The dominant cost to producing software is labor. A common project scope is a three month schedule with a single developer. Estimating a market rate salary of $10K/month, this results in a budget of $30K to deliver software at cost.

Crowdfunding has proven to be successful in raising that level of funding, by mitigating risk to all participants by defining a funding goal. Typically a funding goal is set within a window of time. If the goal is not met, then patrons who already put money down will have their money returned and the producer is not committed to work on the software. With high demand, the goal can be met with potentially low financial risk to an individual patron. For example, if 30,000 people gave $1, the above budget could be met.

Reaching those 30,000 people is another thing altogether, as crowdfunding is an exercise in marketing.

To have a successful crowdfunding campaign, the producer must deliver a message about a future software product that is compelling enough to create demand for it. Common tasks undertaken to make a crowdfunding campaign include producing:

  • A video describing the envisioned product.
  • Marketing copy for said envisioned product published on web, possibly print.
  • Brand merchandise for patrons.
    • Order taking
    • Fulfillment
  • Press campaign.
  • Social media campaign.

Note that the success of the crowdfunding campaign will depend on how effective its message is to the target audience. Each audience is bespoke, meaning that not all things successful for one crowdfunding campaign can be applied to another. Invariably, the software producer must know their audience.

Single developers producing free software might look at the above and say “nope.” Most certainly it is a lot of work, much of which is perhaps outside the comfort level of persons whose focus has only been on coding. It is also not a common practice to use crowdfunding to support free (libre) or open source development. Regardless, if a developer wishes to be paid to work on free software, they will need to get comfortable with pitching their work beforehand to get the funding to do it. Wider-scale use of crowdfunding could bring better agency to the developer and enable the development of larger scope free software projects that would be untenable with volunteer time.

Observations and Closing Thoughts

This post has been a distillation of my thinking about free software and how it can be sustainably funded. From this exercise are some of my personal observations:

If you have a software idea that you want to distribute for free, determine as soon as possible if you want to get paid to make it.

If you don’t care about getting paid, ever, for that work, then GO MAKE IT! Be thankful for whatever gratuity you get from it.

If you do care about getting paid to make the idea, then explore what funding model fits best for the idea. At this point, DO NOT MAKE THE IDEA AND PUBLISH IT.

If you get funding, GO MAKE THE THING. MAKE PEOPLE HAPPY.

If you don’t get funding, let it rest. Move on to the next idea.

If you already produced free software that was built without funding, accept that you will never recover your development cost.

To reiterate, free software requires that its distribution be zero-cost to users. This is excellent for user freedom but comes at the expense of agency for developers: Users can not be compelled to pay developers for their already published work. Developers can however make new features and fixes contingent on funding. I think this position is fair and defensible for the obvious reason that software developers must pay for the costs of living in a material world.

If you’ve made to here, thanks for reading! Feel free to share your thoughts about this post on Mastodon or Reddit.

References

[1]
R. Munroe, “Dependency,” Aug. 17, 2020. Available: https://xkcd.com/2347/
[2]
R. Stallman, “Why open source misses the point of free software - gnu project - free software foundation,” 2024. Available: https://www.gnu.org/philosophy/open-source-misses-the-point.en.html
-1:-- Thoughts on Funding Free Software Development (Post Charles Choi)--L0--C0--2025-11-14T01:20:00.000Z

Joar von Arndt: Decentralized Personal Computing

I have a few different computers. Those machines have different capabilities, form factors, portability, hardware, and software — and yet I still want to do roughly the same work on them. While most of the work I do is with text — reading, writing, editing, programming — Sometimes I want to work on one specific machine because I might need a dedicated graphics card or I need the machine to fit in my pocket. The solution to this is to have work sync automatically between my machines.

This is not a unique problem to have — some common solutions include Microsoft Windows’ Active directory or doing all your work through cloud-based offerings like Google’s Drive or Microsoft’s Sharepoint. There are however a few issues with these solutions. They are almost by definition insecure since they entail sending my data to a third party’s computer1. Services like Proton drive or Koofr at least do the bare minimum of encrypting your files so that only you can access them, but they still keep you reliant on someone else’s infrastructure, and you have to be able to connect to their services in order to access your data.

A better workflow would be (to be able) to work entirely offline and then sync those changes semi-periodically when I am online again. I do not want to have to think about if a machine is connected to the internet or what work I have done on it earlier (or not done). I simply want to pick up (or sit down at) a computer and keep going with whatever I was doing before — all without relying on a centralized host. This of course requires all machines to have their own copy of the data, and for those machines to sync changes to that data between themselves.

This syncing functionality can be offered through a lot of different services or systems. I personally use Syncthing for this, but you could just as well use rsync paired with cron jobs to sync your files securely over ssh. Syncthing is cross platform (so I can use it on android, GNU/Linux, and theoretically Microsoft Windows) and doesn’t rely on port forwarding (and so it doesn’t matter what network I am connected to).

If you want to use rsync and sync to your phone I would probably use something like tailscale paired with termux to run your cron jobs. That way you get a single ip address to hardcode into your rsync scripts and you can move across networks and use your phone’s cellular connection. I actually use tailscale myself (even though it is not free software) to speed up discovery between devices.

Tailscale also allows me to ssh quickly between machines to transfer files that aren’t in my general work-related folders. This is usually stuff that allows me to perform my work (like dotfiles or other configuration). It pairs wonderfully with GNU Emacs’ TRAMP since machines ssh-ing over tailscale don’t need any further authentication (they already authenticated by being on the tailnet) and it also means I don’t have to expose port 22 to the open internet.

I have five different machines that each keep a complete copy of all of my critical files:

  1. Parana
    • This is my server. It does not hold any centralised role in my network, but is configured to serve content to the open web and maintain high uptime. Runs Debian stable.
  2. Nile
    • My desktop computer. Like Parana this is located at my home. This is a more high-powered device meant for user-facing interaction. Runs Arch linux.
  3. Yukon
    • A larger, higher performance laptop that acts as a portable workstation when I am away from home for longer periods of time. Runs Debian testing.
  4. Danube
    • A small, durable, and low-power2 laptop that I can easily toss into my bag. This is probably one of my most used devices because it has a nice keyboard and long battery life. Runs GNU Guix.
  5. Yangtze
    • My phone. In this context it mostly acts as a music player and a way for me to access my grocery list. Runs lineageOS.

One of the biggest advantages to this approach is that not only is the general state of the files kept in sync, but I have five different machines located in different places that all have copies of my data. This means I can maintain the integrity of my data even if I lose my phone (1/5), my laptop is stolen (1/5), or my home burns down when I am away (usually 3/5). I can also wipe my computers — something I do semi-regularly — without worrying about losing anything of importance on them. My desktop and server both have high uptime, so there is always some node on the network that is mirroring changes.

It is however inevitable that conflicts occur when syncing files between machines that are not always online. Thankfully there is a tried-and-tested program that fits with this offline workflow on a distributed number of machines; git.

Git is very useful not just as a collaborative development tool, but also for singular users. Syncthing has an integrated way of dealing with this by retaining copies of files and renaming them. This is good, but it is still an annoying hassle to deal with. Using git is a lot nicer (partly because I can use magit to resolve problems) but git also allows me to see the history of the edits that I have made. Most of my git repositories are not kept on any external server like github’s or codeberg’s, but instead only exist in this pseudo-LAN/VPN that my devices all interact through.

All my machines (yes, even my phone) also posses its own copy of my configuration files for GNU Emacs, and so the way that I interact with my computers is always tailor-made for my preferences and workflows. Because of Emacs I work almost exclusively with files in plaintext (usually formatted using orgdown). Working with plaintext of course makes using git very straightforward, but I still use git for non-plaintext tasks.

Git is harder to use in non-plaintext contexts, but in my experience most binary files do not change often enough to experience many conflicts. That might differ for you however, and you might require some other custom solution.

The end result of this system is that each machine becomes an old-school terminal that interacts with a broader computing system, although one that does not require a centralised server or even a network connection to operate! While all my machines possess complete records of the data and are fully empowered to make arbitrary changes (I am the only user after all) no single computer encompasses the whole of the computing environment. I can always discard one element of the network for another3.

This approach not only maintains your own sovereignty over your data, it doesn’t cost anything and also allows you to make use of your preëxisting storage for a continuos backup solution. It doesn’t stop you from accidentally wiping a given file from all of your machines of course, so adding some sort of air-gapped backup is also necessary.

The modern day computer is increasingly less personal. Smartphones today act more like network terminals than real computing platforms (even though they are many times more powerful than old supercomputers). Building a decentralized system in this fashion is one way of maintaining a computer that is still intimately personal while still offering the advantages of network storage and automatic backups. It allows you to make your own choice about what software to use and how to use that software, and is therefore free in the true essence of free software — and of the enlightenment idea of freedom it is based on. ❦

Footnotes:

1

Also known as “the cloud”. Sending your data to another person requires you trusting them to never get cracked or do anything malicious with your data themselves.

2

When I say low-power I mean it, it only has 4Gb of RAM and 128Gb of storage. I could probably get a machine of similar performance second hand for free.

3

Moving between machines that are all connected to the network is almost seamless and instantaneous, but even setting up a new computer (after purchasing it or wiping the disk) takes only perhaps an hour. After that using the machine is once again as simple as using any other perfectly tailor-made computing device that I own.

-1:-- Decentralized Personal Computing (Post Joar von Arndt)--L0--C0--2025-11-13T23:00:00.000Z

Irreal: Short Yes/No Answers

Like most longer term Emacs users, one of the first things I did was to get rid of the annoying long-form Yes/No questions that required you to answer “yes” or “no” explicitly. That was easy to do. I simply aliased y-or-n-p to yes-or-no-p. The same code is in virtually everybody’s init.el if they started before Emacs 28.

Starting in Emacs 28, the variable use-short-answers was introduced. When non nil it causes yes-or-no-p to call y-or-n-p to ask the question instead of following its normal path.

Lennart Karssen over at Polyomica recently discovered this and wrote a short post about it. He, like almost everyone else hates the long answers. They’re there for a reason, of course, and the documentation for the variable recommends against setting it non nil but I doubt very many folks follow that advice.

I’ve had my original aliasing code for at least 17 years and see no reason to change it. When use-short-answers was first introduced, I thought I should adopt it but I never did and as far as I can see, it doesn’t make any difference.

In the unlikely event that you weren’t aware of how to turn off the requirement for entering long answers, take a look Karssen’s post or just check the documentation for use-short-answers.

-1:-- Short Yes/No Answers (Post Irreal)--L0--C0--2025-11-13T15:35:30.000Z

Paul Jorgensen: Emacs spell check in Windows 11 & MacOS

The winget utility on Windows 11 is a revelation. Here’s how I set it up.

in my main init.el:

;; Check spelling with flyspell and hunspell
;; https://endlessparentheses.com/ispell-and-abbrev-the-perfect-auto-correct.html

(use-package flyspell
:bind
("C-c w s s" . ispell)
("C-c w s i" . endless/ispell-word-then-abbrev)
("C-;" . flyspell-auto-correct-previous-word)
(:map ctl-x-map
("C-i" . endless/ispell-word-then-abbrev) ; see
)
:custom
(ispell-dictionary ews-hunspell-dictionaries)
(flyspell-mark-duplications-flag nil) ;; Writegood mode does this
(org-fold-core-style 'overlays) ;; Fix Org mode bug
(flyspell-prog-text-faces '(font-lock-comment-face font-lock-doc-face))
:defer t
:hook
(text-mode . flyspell-mode)
)

This code from endlesspraentheses goes in my ews.el library:

;; ispell and abbrev, the Perfect™ auto-correct
;;

(add-to-list ‘ispell-skip-region-alist ‘(“^\s*:PROPERTIES\:$” . “^\s*:END\:$”))

(defun endless/simple-get-word ()
(car-safe (save-excursion (ispell-get-word nil)))
)

(defun endless/ispell-word-then-abbrev (p)
“Call `ispell-word’, then create an abbrev for it.
With prefix P, create local abbrev. Otherwise it will
be global.
If there’s nothing wrong with the word at point, keep
looking for a typo until the beginning of buffer. You can
skip typos you don’t want to fix with `SPC’, and you can
abort completely with `C-g’.”
(interactive “P”)
(let (bef aft)
(save-excursion
(while (if (setq bef (endless/simple-get-word))
;; Word was corrected or used quit.
(if (ispell-word nil ‘quiet)
nil ; End the loop.
;; Also end if we reach `bob’.
(not (bobp)))
;; If there’s no word at point, keep looking
;; until `bob’.
(not (bobp)))
(backward-word)
(backward-char))
(setq aft (endless/simple-get-word)))
(if (and aft bef (not (equal aft bef)))
(let ((aft (downcase aft))
(bef (downcase bef)))
(define-abbrev
(if p local-abbrev-table global-abbrev-table)
bef aft)
(message “\”%s\” now expands to \”%s\” %sally”
bef aft (if p “loc” “glob”)))
(user-error “No typo at or before point”)))
)

Emacs on Mac, be it NS or Cocoa, works well with the brew installed hunspell.

brew install hunspell

In my mac-ns.el (which loads in my init.el):

(use-package flyspell
:custom
(ispell-program-name "hunspell")
)

All I do here is set the hunspell executable.

In Windows 11 as administrator I run the following:

winget install fsfhu.hunspell

… and download the dictionaries as described by VXLabs here. I placed the extracted files in a synced dict directory linked to from my home.

(use-package flyspell
:custom
(ispell-program-name "~/AppData/Local/Microsoft/WinGet/Links/hunspell.exe")
(ispell-local-dictionary "en_US")
(ispell-local-dictionary-alist '(("en_US" "[[:alpha:]]" "[^[:alpha:]]" "[']" nil ("-d" "en_US") nil utf-8)))
:init
(setopt
ispell-hunspell-dict-paths-alist '(("en_US" "~/plrjorg/dict/en_US.aff"))
)
)

For completion’s sake, here’s the one little defcustom from Emacs Writing Studio:

(defcustom ews-hunspell-dictionaries "en_US"
"Comma-separated list of Hunspell dictionaries."
:group 'ews
:type 'list)

Apologies for the janky formatting yet again.

-1:-- Emacs spell check in Windows 11 & MacOS (Post Paul Jorgensen)--L0--C0--2025-11-12T20:37:47.000Z

Irreal: Finding The File At Point

I just discovered a useful trick over at Ruslan’s Tech Blog. It’s about finding the file at point. Ruslan does this a lot. I, on the other hand, hardly every do it but I have gotten used to typing Ctrl+c Ctrl+o to follow a link in an Org buffer. Despite using the goto-addr package, this doesn’t work reliably everywhere.

Ruslan was also bothered by the difficulty of opening a file at point—although his normal usage didn’t involve Org. Like many of us, he thought he’d just write a quick command to do what he wanted but before embarking on that, he read the documentation for find-file and discovered that the functionality he wanted was already there.

If the point is on a file path, you can invoke Meta+x find-file-at-point but that’s a lot of typing. It’s a bit less typing if you use its ffap alias but perhaps still too much. Instead, you can just type Ctrl+x Ctrl+f as usual and then Meta+n to follow the link at point. It’s a nice solution because you do what you always do when you want to open a file and then type Meta+n instead of a file path to open the file at point. Best of all, you don’t have to do anything to enable this. It’s the default Emacs behavior.

-1:-- Finding The File At Point (Post Irreal)--L0--C0--2025-11-12T16:00:24.000Z

Jack Baty: What do I even mean by "Simple?"

For nearly two years I’ve been telling myself to Reduce & Simplify. For short periods, I’ve almost done that, but entropy takes over and I once again overcomplicate everything.

Could the problem be that I’m not sure what I mean by “Simple”?

One day, it feels simple to use only Emacs and a browser on Linux installed on boring hardware. The next day, simple means using the default Notes, Mail, and Reminders app on macOS. Then on another day, a notebook and pen are my definition of “simple”. What happens is that I end up alternating between all of these so-called simple workflows, and I’m back to chaos.

Simple is “One camera, one lens”. But which camera and which lens? If I change my mind every other day, it’s no longer one camera, one lens. It’s definitely not simple.

Maybe I’m incapable of simplifying. Maybe what I’m doing now is as simple as it gets. I hope not, because what I’m doing now is crazy-making.

What I’d think simplification looks like for me:

  • Linux or macOS? Pick one and run with it. If I still need macOS for scanning or something, turn the Mac into an appliance for only doing that. Stop this waffling.
  • Choose 3 cameras. One for the pocket, everywhere. One for when I’m out and don’t mind carrying a camera. One for “serious” work. I don’t think I can limit it further than that.
  • One notebook. OK, maybe two notebooks. One for logging/planning and one as a personal journal.

The problem might be that I want to be one kind of person, but I’m actually a different kind of person. They are incompatible.

Still, it’s worth a try.

P.S. I’m typing this in NeoVim because maybe that’s simpler than using Emacs? 🙄

✍️ Reply by email
-1:-- What do I even mean by "Simple?" (Post Jack Baty)--L0--C0--2025-11-12T10:15:25.000Z

Alvaro Ramirez: Want a WhatsApp Emacs client? Will you fund it?

Like it or not, WhatsApp is a necessity for some of us. I wish it weren't the case, but here we are.

Given the circumstances, I wish I could use WhatsApp a little more on my terms. And by that, I mean from an Emacs client, of course. Surely I'm not the only one who feels this way, right? Right?! Fortunately, I'm not alone.

With that in mind, I've been hard at work prototyping, exploring what's feasible. Spoiler alert: it's totally possible, though will require a fair bit of work.

Thankfully, two wonderful projects offer a huge leg up: wuzapi and whatsmeow.

wuzapi offers a REST API on top of whatsmeow, a Go library leveraging WhatsApp's multi-device web API.

Last week, I prototyped sending a WhatsApp message using wuzapi's REST API.

I got there fairly quickly by onboarding myself on to wuzapi using its web interface and wiring shell-maker to send an HTTP message request via curl. While these two were enough for a quick demo, they won't cut it for a polished Emacs experience.

While I can make REST work, I would like a simpler integration under the hood. REST is fine for outgoing messages, but then I need to integrate webhooks for incoming events. No biggie, can be done, but now I have to deal with two local services opening a couple of ports. Can we simplify a little? Yes we can.

You may have seen me talk about agent-shell, my Emacs package implementing Agent Client Protocol (ACP)… Why is this relevant, you may ask? Well, after building a native Emacs ACP implementation, I learned a bit about json-rpc over standard I/O. The simplicity here is that we can bring bidirectional communication to an Emacs-owned process. No need for multiple channels handling incoming vs outgoing messages.

So where's this all going?

I've been prototyping some patches on top of wuzapi to expose json-rpc over standard I/O (as an alternative to REST). This prototype goes far beyond my initial experiment with sending messages, and yet the Emacs integration is considerably simpler, not to mention looking very promising. Here's a demo showing incoming WhatsApp messages, received via json-rpc, all through a single Emacs-owned process. Look ma, no ports!

It's feasible (but still lots to do)

These early prototypes are encouraging, but we've only scratched the surface. Before you can send and receive messages, you need to onboard users to the WhatsApp Emacs client. That is, you need to create a wuzapi user, manage/connect to a session, authorize via a QR code, and more. You'll want this flow to be realiable and that's just onboarding.

From there, you'll need to manage contacts, chats, multiple message types, incoming notifications… the list goes on. That's just the Emacs side. As mentioned, I've also been patching wuzapi. My plan is to upstream these changes, rather than maintaining a fork.

Will you fund the work?

I've prototyped quite a few things now, including the onboarding experience with QR code scanning. At this point, I feel fairly optimistic about feasibility, which is all pretty exciting! But there's a bunch of work needed. Since going full-time indie dev, I have the time available (for now), but it's hard to justify this effort without aiming for some level of sustainability.

If you're interested in making this a reality, please consider sponsoring the effort, and please reach out to voice your interest (Mastodon / Twitter / Reddit / Bluesky).

Reckon a WhatsApp Emacs client would help you stay focused at work (less time on your phone)? Ask your employer to sponsor it too ;-)

-1:-- Want a WhatsApp Emacs client? Will you fund it? (Post Alvaro Ramirez)--L0--C0--2025-11-12T00:00:00.000Z

Sacha Chua: 2025-11-10 Emacs news

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

View org source for this post

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

-1:-- 2025-11-10 Emacs news (Post Sacha Chua)--L0--C0--2025-11-11T01:16:11.000Z

Irreal: Setting avy-timeout-seconds To A More Reasonable Value

As longtime Irreal readers know, I am an Avy fanatic and use it as my principal means of buffer navigation. For a long time, I mostly used avy-goto-word-1 but it can only be used to search for the beginning of words. Four years ago, Karthink Chikmagalur published a post that recommended using avy-goto-char-timer exclusively. For some reason, I ignored his post at the time but a couple of years ago I was reacquainted with his recommendation and resolved to use avy-goto-char-timer more.

One day I suddenly realized that I was, in fact, using it exclusively and couldn’t even remember my binding for avy-goto-word-1. It solves the problem of avy-goto-word-1 being able to find only the beginning of words.

As the name suggests, avi-goto-char-timer will accept input chars until there’s no input for the timeout value. Then it will present a tree of potential targets having those characters. The default timeout value is 0.5 seconds so if you stop typing for half a second, avy-goto-char-timer will present you with a tree of targets.

Lately—perhaps because I mostly work with my laptop on my lap or perhaps because of declining reaction times—I’ve found that half a second isn’t quite long enough. It often produces suboptimal outcomes, resulting in spurious characters being added to the text in the worst case.

As often happens, I put up with this infelicity for some time before I finally got fed up enough to do something about it. The “something” in this case was trivial. I simply increased the timeout value to 1.5 seconds. That may be a little long but it seems fine so far. I can, of course, always decrease it a bit if it turns out to hold things up.

-1:-- Setting avy-timeout-seconds To A More Reasonable Value (Post Irreal)--L0--C0--2025-11-10T15:18:27.000Z

ablatedsprocket: Configuring Rootless Podman

It's been a while since I've written a post, but that doesn't mean I've been idle. I really like the idea of the separation involved with running things in containers. Until now, I accomplished this using Docker and Docker Compose. After spending some time with NixOS, I looked through its packages and found that everything I had running in Docker containers was available in Nix and enjoyed the opportunity to run these services under Systemd. Now that I'm back to using Arch, I decided to try getting the best of both worlds.

-1:-- Configuring Rootless Podman (Post ablatedsprocket)--L0--C0--2025-11-10T06:00:00.000Z

Kisaragi Hiu: Is it faster to (read) Elisp or parse JSON from Emacs?

I got curious while working on a project and did a quick test, this is the result.

My main point is effectively RPC, so I have control over the production of the data. As such I'm only going to be comparing the parsing speed for a very basic structure.

How

First prepare the basic test file:

;; /tmp/bench.el

(defun generate ()
 (require 'json)
 (let ((list nil))
 (dotimes (i 10000000)
 (push i list))
 (with-temp-file "10million.el"
 (insert (prin1-to-string list)))
 (with-temp-file "10million.json"
 ;; json-serialize wants a vector, so I'll just use json-encode instead
 ;; …I mean, I could've also just done (vconcat nil [])
 (insert (json-encode list)))))

I was running this in shell instead of running it in my main Emacs instance. So I ran it like this:

-1:-- Is it faster to (read) Elisp or parse JSON from Emacs? (Post Kisaragi Hiu)--L0--C0--2025-11-10T04:28:37.000Z

Protesilaos Stavrou: Emacs: complete examples for Modus themes derivatives

I just expanded the manual of the modus-themes with complete step-by-step examples on how to define a derivative theme. Here is the commit:

commit c94938ff794d043447ed4ffe9b55f1031039f667
Author: Protesilaos Stavrou <info@protesilaos.com>
Date:   Mon Nov 10 13:02:49 2025 +0200

  Greatly expand the manual with complete examples of creating Modus derivatives

  This covers the basic and more advanced use cases. It also is for both
  private use and making new packages.

 doc/modus-themes.info | 588 +++++++++++++++++++++++++++++++++++++-------------
 doc/modus-themes.org  | 278 +++++++++++++++++++++++-
 2 files changed, 711 insertions(+), 155 deletions(-)

The relevant sections and their structure:

If something is unclear, you are welcome to contact me.

-1:-- Emacs: complete examples for Modus themes derivatives (Post Protesilaos Stavrou)--L0--C0--2025-11-10T00:00:00.000Z

Irreal: Org Tables In Comments And Docstrings

If you’ve been using Org-mode for a while, you’re probably familiar with its table editing functionality and may even know that you can use that functionality anywhere in Emacs with orgtbl-mode. For most non-Org applications, of course, those tables will be in some sort of comment.

Andrew over at the Listful Andrew site has a useful post on how to do that. It’s a little more finicky than you might think because the editing won’t work if the table lines are commented out. It’s easy to work around that, of course, but Andrew offers some other strategies.

When you’re in Elisp, the easiest way to add a table to a comment is to add it do a Docstring. That’s easy and the table can be edited at will. Andrew offer another method using his custom description macro. Most of us won’t have that macro, of course, but it’s another strategy.

Finally, Andrew considers adding tables to Bash comments. The problems are similar to those encountered with Elisp: you can’t edit tables whose rows are commented out. As with Elisp, that’s easily worked around but again there are better ways.

One way is to use the null command : to introduce the comment string. See Andrew’s post for the details. Another way is to use a here document or a here string. Again, see Andrew’s post for the details.

Tables in comments isn’t something that you need all the time but it’s nice to have to ability to add them when you do. Andrew’s post is a nice demonstration of how to do that.

-1:-- Org Tables In Comments And Docstrings (Post Irreal)--L0--C0--2025-11-09T15:28:10.000Z

tusharhero: ANN: Modus Gotham is here

~94 words. ~0 minutes.

Inspired by Magnus's blog post on creating a theme based on Modus, I decided to try my hand at implementing the gotham-theme using modus-themes.

This is my first time creating a theme, so don't expect it to be perfect yet.

https://codeberg.org/tusharhero/modus-gotham

You can install it via package-vc for now.

It took me approximately 2.5 hours to get this far.

-1:-- ANN: Modus Gotham is here (Post tusharhero)--L0--C0--2025-11-09T05:00:00.000Z

George Huebner: disaster.el + zig cc = Budget godbolt

Disaster is an Emacs package authored by the venerable Justine Tunney that allows disassembling C/C++ and Fortran code from the comfort of your source editing buffer. I really like this idea, but most of the time I’m interested in x86_64 assembly instead of my aarch64 host platform, so I decided to hack on cross compilation support using Zig as a C/C++ cross compiler!

I’m using disaster because its simplicity fits my use case, but you should be able to use the same idea with other packages like

RMSbolt
Has support for tons of languages (and bytecode, not just assembly), and you can track point across source and compilation buffers
Beardbolt
Rewrite of RMSbolt that is faster/simpler than RMSbolt, but only supports C/C++/Rust

PoC Or GTFO

Emacs Lisp
(use-package disaster
    :config
  (setq disaster-cflags (setq disaster-cxxflags "-Wno-everything -g"))
  (setq disaster-assembly-mode 'nasm-mode)
  :init
  (define-advice disaster (:around (fn &rest args) cross-compile)
    (interactive)
    ;; OPTIONAL: support for non-file buffers
    (setq arg (or args
                    (list (if-let* ((buf (current-buffer))
                                    (buf-name (buffer-name buf))
                                    (file (buffer-file-name (current-buffer))))
                              file
                            (make-temp-file
                             (file-name-base buf-name) nil
                             (cond ((eq major-mode 'fundamental-mode) (c-or-c++-ts-mode))
                                   ((member major-mode '(c-mode c-ts-mode)) ".c")
                                   ((member major-mode '(c++-mode c++-ts-mode)) ".cpp")
                                   ((eq major-mode 'fortran-mode) ".f")
                                   (t (file-name-extension buf-name)))
                             (buffer-string)))))
          ;; replace `doit` with `apply fn args` if you get rid of this
          doit (lambda () (if args (apply fn arg)
                            (with-temp-buffer (apply fn arg)))))
    ;; END-OPTIONAL
    (if (and current-prefix-arg (mapc (lambda (exe)
                                        (or (executable-find exe) (user-error "disaster: %s not found" exe)))
                                      '("zig" "jq")))
        (let* ((monch (lambda (prompt collection default)
                        (completing-read prompt (split-string collection " ") nil nil nil nil default)))
               (file-exists-wrapped (symbol-function #'file-exists-p))
               (targets (split-string (shell-command-to-string "zig targets | jq -r '.arch,.os,.abi | join(\" \")'") "\n" t))
               (host-target (mapcar (lambda (s) (car (split-string s "[ \.\t\n\r]+"))) (split-string (shell-command-to-string "zig env | jq -r '.target'") "-")))
               (target-arg (apply #'format " -target %s-%s-%s" (cl-mapcar monch '("Arch: " "OS: " "ABI: ") targets host-target)))
               (disaster-cc "zig cc")
               (disaster-cxx "zig c++")
               (disaster-cflags (concat disaster-cflags target-arg))
               (disaster-cxxflags (concat disaster-cxxflags target-arg)))
          (with-environment-variables (("CC" disaster-cc)
                                       ("CXX" disaster-cxx)
                                       ("CFLAGS" disaster-cflags)
                                       ("CXXFLAGS" disaster-cxxflags))
            (cl-letf (((symbol-function #'file-exists-p)
                       (lambda (file)
                         (unless (string= "compile_commands.json"
                                          (file-name-nondirectory file))
                           (funcall file-exists-wrapped file)))))
              (funcall doit))))
      (funcall doit))
    ;; OPTIONAL: Put point in assembly buffer
    (switch-to-buffer-other-window disaster-buffer-assembly)))

This requires zig and jq to be in Emac’s exec-path, although I’m sure you could use Elisp to do the JSON parsing instead, especially now that Emacs 30.1 ships with its own JSON implementation. Most sane people would object to my usage of cl-letf and advice instead of a separate wrapper function; this would probably be more readable as a patch instead, but I like having a snippet that you can quickly try out with eval-last-sexp.

Caveat emptor: this falls apart for large projects, poorly behaved Makefiles, and probably CMake (I tried ameliorating the latter issue upstream, but I don’t use CMake that often so YMMV). Also, this definitely doesn’t count as a “Compiler Explorer” in the strict sense because you’re using the same version of LLVM regardless of target; you might be able to do something like leverage nixpkgs’ cross compilation support to build older cross-compilers, but you’re probably better off using Docker or Godbolt at that point.

-1:-- disaster.el + zig cc = Budget godbolt (Post George Huebner)--L0--C0--2025-11-09T03:24:14.000Z

George Huebner: Speedier elisp-refs-* with Dumb Grep

Helpful is a fantastic Emacs package that drastically improves the builtin help-mode. One of the particularly nice features is finding references to a particular symbol. Unfortunately it can be painfully slow in practice due to actually parsing every loaded Elisp file:

Emacs Lisp
(require 'benchmark)
(benchmark-elapse (elisp-refs-function #'car))
24.001221

Instead of walking the ASTs of every file, why not do a regex search?

It sacrifices correctness (and completely ignores the type of the symbol), but it turns out to be orders of magnitude faster in practice. Bonus points for using a fast tool like ripgrep and extra bonus points for completing the work asynchronously so as not to block Emacs’s main thread.

I don’t mean to denigrate elisp-refs; the author clearly has put a lot of thought into performance and it’s only natural that using an approach that heavily cuts corners together with a tool implemented in optimized machine code instead of Elisp (which is especially hampered by GC performance) will lead to faster results.

I’m a ripgrep junkie and I prefer it for grokking most codebases, but the speed comes at the cost of having to sift through many false positives.

I use the wonderful deadgrep package to do just that:

Emacs Lisp
(when (locate-library "deadgrep")
  (require 'deadgrep)
  (fset 'deadgrep--arguments-orig (symbol-function #'deadgrep--arguments))
  (define-advice helpful--all-references (:override (button) fysh/use-deadgrep)
    (cl-letf* (((symbol-function 'deadgrep--arguments)
                (lambda (&rest args)
                  `("--follow" "--type=elisp" "--type=gzip" "--search-zip" ,@(butlast (apply #'deadgrep--arguments-orig args)) ,lisp-directory ,(-first (lambda (p) (string-suffix-p "/share/emacs/site-lisp" p)) load-path)))))
      (deadgrep (symbol-name (button-get button 'symbol)) default-directory))))

The code is quite hacky because deadgrep is not designed to allow passing multiple directories in a single search, but this gets the job done.

Emacs Lisp
(with-temp-buffer
  (let ((button (make-button (point-min) (point-max)))
        (time-to-draw)
        (time-to-completion))
    (button-put button 'symbol #'car)

    (setq time-to-completion (benchmark-elapse
                               (setq time-to-draw (benchmark-elapse (helpful--all-references button)))
                               (while deadgrep--running (sit-for 0.1 'nodisp))))
    (format "Time to first draw: %s\nTime to completion: %s" time-to-draw time-to-completion)))
Time to first draw: 0.084542
Time to completion: 38.184606

In this pathological case the total time is slower than using elisp-refs-function because there are almost four times as many matches because of comments/docstrings and partial matches like mapcar or car-safe (including symbols that aren’t functions like byte-car). The major difference is that while the performance of elisp-refs-* functions1 are roughly constant regardless of the total number of references to a symbol, using ripgrep is significantly faster for terms with fewer than 10k matches (not to mention that you can browse the results immediately).

If you want to remove the partial matches, you could use the following advice instead:

Emacs Lisp
(define-advice helpful--all-references (:override (button) fysh/use-deadgrep)
  (cl-letf* (((symbol-function 'deadgrep--arguments)
              (lambda (&rest args)
                `("--follow" "--type=elisp" "--type=gzip" "--search-zip" ,@(butlast (apply #'deadgrep--arguments-orig args) 3) "--no-fixed-strings" "--" ,(car args) ,lisp-directory ,(-first (lambda (p) (string-suffix-p "/share/emacs/site-lisp" p)) load-path)))))
    (deadgrep (format "(\\(|#?'| )(%s) " (symbol-name (button-get button 'symbol))) default-directory)))

This unfortunately will highlight the entire match instead of just the capturing group, so I prefer not to use it (althgough the speed is mostly the same, if not a bit faster).


  1. elisp-refs-symbol is faster than its counterparts due to reduced implementation complexity ↩︎

-1:-- Speedier elisp-refs-* with Dumb Grep (Post George Huebner)--L0--C0--2025-11-09T03:07:32.000Z

Protesilaos Stavrou: Emacs: ‘standard-themes’ version 3.0.0

The standard-themes are a collection of light and dark themes for GNU Emacs. The standard-light and standard-dark emulate the out-of-the-box looks of Emacs (which technically do NOT constitute a theme) while bringing to them thematic consistency, customizability, and extensibility. Other themes are stylistic variations of those.

In practice, the Standard themes take the default style of the font-lock and Org faces, complement it with a wider and harmonious colour palette, address many inconsistencies, and apply established semantic patterns across all interfaces by supporting a large number of packages.

Below are the release notes.


Version 3.0.0 on 2025-11-09

This major version makes Standard build on top of my Modus themes. The latter provides extensive face/package coverage and a wide range of customisation options. As a result, the Standard themes retain their design while giving more control to the user.

These release notes are essentially the same as what I wrote earlier today for my ef-themes package, which is now also built on top of my Modus themes: https://protesilaos.com/codelog/2025-11-09-emacs-ef-themes-2-0-0/.

In short:

  • User options that were provided by the Standard themes are now mere aliases for their Modus counterparts.
  • Commands that were defined by the Standard themes are now reduced to convenience wrappers that build on top of Modus.
  • The new minor mode standard-themes-take-over-modus-themes-mode can be enabled to make all Modus commands that load a theme only consider the Standard themes. This is effectively the opposite of enabling the modus-themes-include-derivatives-mode or using one of the Standard commands to load just a Standard theme (like standard-themes-rotate).
  • The manual of the Modus themes covers everything from the basics to advanced topics on how to use and customise the themes. Evaluate (info "(modus-themes) Top") or visit https://protesilaos.com/emacs/modus-themes.

You are welcome to contact me if something is unclear.

-1:-- Emacs: ‘standard-themes’ version 3.0.0 (Post Protesilaos Stavrou)--L0--C0--2025-11-09T00:00:00.000Z

Protesilaos Stavrou: Emacs: ef-themes version 2.0.0

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

Below are the release notes.


Version 2.0.0 on 2025-11-09

The Ef themes are now derived from my Modus themes. This means that they inherit the wide face coverage and extensive customisability of Modus, while retaining their stylistic flair.

The Ef themes no longer provide any user options of their own. Each of the options we had before is now an alias for the Modus equivalent. As part of this transition, the Ef themes actually gain new customisation options, which are documented herein.

Furthermore, the Ef themes do not define any commands to load a theme. What we had before is once again an alias for the equivalent Modus command.

The manual of the Ef themes describes these compatibility arrangements. Further documentation and code samples are available in the manual of the Modus themes:

Old user options and hooks are mere aliases for Modus options

Old name Is alias for CURRENT NAME
ef-themes-disable-other-themes modus-themes-disable-other-themes
ef-themes-to-toggle modus-themes-to-toggle
ef-themes-to-rotate modus-themes-to-rotate
ef-themes-italic-constructs modus-themes-italic-constructs
ef-themes-bold-constructs modus-themes-bold-constructs
ef-themes-variable-pitch-ui modus-themes-variable-pitch-ui
ef-themes-mixed-fonts modus-themes-mixed-fonts
ef-themes-headings modus-themes-headings
ef-themes-completions modus-themes-completions
ef-themes-prompts modus-themes-prompts
ef-themes-common-palette-overrides modus-themes-common-palette-overrides
ef-themes-post-load-hook modus-themes-after-load-theme-hook
ef-themes-after-load-theme-hook modus-themes-after-load-theme-hook

Please read their respective documentation strings.

If you use Ef and possibly other Modus derivatives, you may prefer to switch all your user options to the Modus ones. This way you can keep a unified configuration for all your themes.

Fewer bold and italic faces by default, more as an opt-in clause

In the past, the Ef themes did not provide an option to disable the extensive use of a bold font weight and italic font slant. Whereas now those are controlled by the user options modus-themes-bold-constructs and modus-themes-italic-constructs. By default, when they are nil, bold and italics are used only when necessary. Set these user options to t to have bold and italics in more places.

Loading only Ef themes with the convenience wrappers we provide

All the old commands Ef provided for loading one of its themes will still work as before, meaning that they will only ever show and load a theme that belongs to the Ef collection.

Internally, these commands are now using the Modus infrastructure and are then limiting the set of themes to the Ef collection. They are thus convenience wrappers around the equivalent Modus commands.

  • ef-themes-toggle
  • ef-themes-rotate
  • ef-themes-select
  • ef-themes-load-random
  • ef-themes-load-random-dark
  • ef-themes-load-random-light

Additionally, the commands ef-themes-list-colors and ef-themes-list-colors-current use the relevant Modus functionality under the hood while working only with the Ef themes.

Combining core Modus themes with all their derivatives

The minor mode modus-themes-include-derivatives-mode makes all the theme-loading commands that Modus defines consider all core and derivative themes. This means that something like modus-themes-select will offer modus-operandi and ef-summer as two of the many possible candidates.

In this scenario, the Modus and Ef collections become part of a larger family of themes as opposed to only considering one or the other (Loading only Ef themes with the convenience wrappers we provide). Enable modus-themes-include-derivatives-mode and then access them all with the following commands:

  • modus-themes-toggle
  • modus-themes-rotate
  • modus-themes-select
  • modus-themes-load-random
  • modus-themes-load-random-dark
  • modus-themes-load-random-light
  • modus-themes-list-colors
  • modus-themes-list-colors-current

Consult the manual of the Modus themes for further details and/or read the documentation string of each command.

Taking over the Modus commands altogether

The minor mode ef-themes-take-over-modus-themes-mode makes all Modus commands that load a theme consider only Ef themes. This is the opposite of allowing different theme collections to be blended together (Combining core Modus themes with all their derivatives). It effectively is the same as using one of the convenience wrapper commands we already provide (Loading only Ef themes with the convenience wrappers we provide).

This minor mode exists to accommodate the needs of users who install both the Modus and Ef theme packages (and possibly other Modus derivatives). They can maintain a single/shared configuration and then decide when to enable ef-themes-take-over-modus-themes-mode to switch to using just the Ef themes.

For example, in the morning the user only wants to consider the Modus themes, but during the evening they only likee the Ef themes. In this scenario, a key binding to, say, modus-themes-rotate does not need to be updated: it internally reads only Ef themes when ef-themes-take-over-modus-themes-mode is enable. When this minor mode is disabled, that same key binding will revert to doing what it did before (load only a core Modus theme or Modus plus derivatives if modus-themes-include-derivatives-mode is enabled).

More semantic palette mappings

Modus has always had a more comprehensive palette than Ef. Now they are on par. Concretely, this means that users can customise more of the theme’s style to their liking. Use the commands that list/preview a palette to learn about all the available options.

The manual of the Modus themes covers the palette and user-defined overrides at great length. It also includes code samples that you can use as a starting point. And if something is unclear, you are welcome to contact me.

Many more faces are covered

The wide face/package coverage of Modus is now inherited by the Ef themes. If some interface you are using does not look right, then the underlying faces are probably not supported yet. Contact me and I will take care of it right away.

-1:-- Emacs: ef-themes version 2.0.0 (Post Protesilaos Stavrou)--L0--C0--2025-11-09T00:00:00.000Z

Irreal: Swift Development in Emacs

Here’s some good news for iOS/macOS developers who are also Emacs users. Until now, the only reasonable way to develop for iOS was to use Apple’s Xcode. Xcode is a perfectly good editor and has the necessary integration to make it easy to develop for iOS but it’s not Emacs. I’m pretty sure that most Emacs users would consider it a tax on iOS development.

Now, thanks to Mikael Konradsson, there’s an alternative. For the last couple of years, Konradsson has been working on moving Swift development to Emacs. That’s harder than you might think because he also had to provide the interfaces to the previewers, simulators and build tools that are important in iOS development. It even has an interface to the Apple documentation system.

Take a look at his post to see a list of its features. His GitHub repository has even more information. Konradsson describes it as still Alpha quality software but he has been using it for his own development during those two years. One of the commenters asked if it was on Melpa and Konradsson said that he felt it needed to mature a bit more first. The paranoid may therefore want to wait a bit but it’s hard to see any harm in checking it out.

One of the reasons I’ve never ventured into iOS development—despite occasional itches to do so—is that the thought of learning and navigating the Xcode system seemed too daunting. Even using Konradsson’s package, it probably wouldn’t be easy for the newcomer, but at least it would be Emacs. I’ll be interested to see how this package plays out. If it lives up to its author’s description, it could be a game changer for Emacs iOS developers.

Update [2025-11-12 Wed 11:06]: Fixed link.

-1:-- Swift Development in Emacs (Post Irreal)--L0--C0--2025-11-08T16:36:30.000Z

Jack Baty: I may have to use macOS on the desktop

I’m trying to get everything running smoothly on the Linux machines. I really am. And I’m close, but I’m not there yet, and I’m not sure if I’ll ever get there.

Many of the apps I use on macOS are also available on Linux. This is awesome. It’s the ones I love, but need to leave behind that are causing all the trouble.

Most of the problems are around photo processing. I’ve spent many (many!) hours learning and testing Darktable for RAW processing. It’s a powerful tool with a lot of clever ideas, some of which I actually prefer to its Mac counterparts. However, Darktable is not at all pleasant to use. Once the cleverness and new-shiny factors are past, I’m forced to live in a clumsy, awkward, unpleasant, unattractive environment. I miss Capture One dearly. Capture One gets me results I like quickly and easily. It’s better.

Then there’s scanning. I’ve spent years wrangling SilverFast to a point where I don’t hate it. Recent updates have introduced the feature of scanning multiple (3, in my case) frames at once, making it much faster. I used to use Vuescan, and it’s available on Linux, so I tried it. So so slow. And it does a pretty poor job with color film.

With digital camera scans, nothing beats Negative Lab Pro for doing inversions. NLP requires Lightroom Classic, so I’m kind of stuck there. I tried the Negadoctor feature of Darkroom and, while feasible, inversions are slow and tedious.

Photography is not just something I tinker with occasionally. It’s my most enjoyable hobby. I don’t think I want to suffer through it, just so I can use Linux.

There are several other apps that I seriously miss from macOS. BBEdit is still unbeatable for ease of use, stability, and capabilities when it comes to manipulating text. Tinderbox is one of a kind for outlining and notes. There’s nothing on Linux comparable with OmniFocus for task management. And so on.

But the deal-breaking omission might be Messages. Everyone I communicate with regularly uses Apple Messages and Facetime, exclusively. I can’t stand typing on my phone, so having to hear an alert, grab my phone, and fumble my way through a reply is maddening. Also, I can’t quickly send people links or photos from where I am. How am I supposed to share that hilarious meme if it’s so much effort?

On the other hand, I love using the Framework laptop when away from my desk. I like the keyboard better than the MacBook Air’s. Knowing I can easily upgrade or fix things (inexpensively) for years is very compelling.

So all this to say that I may end up using a Mac on the desktop and Linux on the laptop. I swore I’d never do that again. Between sync, paths, configuration issues, filename case mismatches, and wildly different key bindings, using both is a royal pain in the ass.

This rambling post is just me working through all of this. I’m typing this post using BBEdit on the Mac Mini, and I gotta say that having the standard Emacs keybindings everywhere is a compelling case for macOS for me.

I’ll keep you posted.

✍️ Reply by email
-1:-- I may have to use macOS on the desktop (Post Jack Baty)--L0--C0--2025-11-08T14:56:06.000Z

Magnus: Making a theme based on modus

In modus-theme 5.0.0 Prot introduced a structured way to build a theme based on modus. Just a few days ago he released version 5.1.0 with some improvements in this area.

The official documentation of how to build on top of the Modus themes is very good. It's focused on how to make sure your theme fits in with the rest of the "modus universe". However, after reading it I still didn't have a good idea of how to get started with my own theme. In case others feel the same way I thought I'd write down how I ended up getting started.

The resulting theme, modus-catppuccin, can be found here.

A little background

I read about how to create a catppuccin-mocha theme using modus-vivendi through modus' mechanism of overrides. On Reddit someone pointed out that Prot had been working on basing themes on modus and when I checked the state of it he'd just released version 5.0.0. Since I'm using catppuccin themes for pretty much all software with a GUI I thought it could be interesting to see if I could make a modus-based catppuccin theme to replace my use of catppuccin-theme.

I'm writing the rest as if it was a straight and easy journey. It wasn't! I made a few false starts, each time realising something new about the structure and starting over with a better idea.

Finding a starting point

When reading what Prot had written about modus-themes in general, and about how to create themes based on it, in particular, I found that he's ported both standard-themes and ef-themes so they now are based on modus. Instead of just using them for inspiration I decided that since standard-themes is so small I might as well use it as my starting point.

Starting

I copied all files of standard-themes to an empty git repository, then I

  • deleted all but one of the theme file
  • copied the remaining theme file so I had four in total (one for each of the catppuccin flavours)
  • renamed constants, variables, and functions so they would match the theme and its flavours
  • put the colours into each catppuccin-<flavour>-palette
  • emptied the common palette, modus-catppuccin-common-palette-mappings
  • made sure that my use of modus-themes-theme was reasonable, in particular the base palette (I based the light flavour on modus-operandi and the three dark flavours on modus-vivendi)

The result can be seen here.

At this point the three theme flavours contained no relevant mappings of their own, so what I had was in practice modus-operandi under a new name and modus-vivendi under three new names.

Adding mappings for catppuccin

By organising the theme flavours the way outlined above I only need to add mappings to modus-catppuccin-common-palette-mappings because

  1. each flavour-specific mapping adds its colour palette using the same name (that's how catppuccin organises its colors too, as seen here)
  2. each flavour-specific mapping is combined with the common one
  3. any missing mapping is picked up by the underlying theme, modus-operandi or modus-vivendi, so there will be (somewhat) nice colours for everything

I started out with the mappings in the dark standard theme but then I realised that's not the complete list of available mappings and I started looking at the themes in modus-themes itself.

Current state of modus-catppuccin

I've so far defined enough mappings to make it look enough like catppuccin for my use. There are a lot of possible mappings so my plan is to add them over time and use catppuccin-theme for inspiration.

-1:-- Making a theme based on modus (Post Magnus)--L0--C0--2025-11-08T08:45:00.000Z

Irreal: Bending Emacs – Episode 5: Ready Player Mode

Álvaro Ramírez is back with the fifth episode of Bending Emacs. This video is about Ready Player Mode, his version of a media player in Emacs.

A year ago, Ramírez mostly moved away from streaming his music and went back to buying and playing his own copies of the music he liked. Of course, he wanted to do this from Emacs so he wrote his own Emacs-based music player. As Ramírez says, this is less of an effort than you might suppose. He leveraged Dired to keep track of the files and mpv or one of several other music players to do the actual playing.

You can get a comprehensive tour of Ready Player Mode here. The main point, at least from my point of view, is that you can move one more task into Emacs. That said, I’ve been lazy and still haven’t arranged to play music from within Emacs. I’m still using the Apple Music App for that. Partly that’s because some time ago I moved all my music to the iCloud so that it would be available on all my devices but mostly it’s because I’ve been too lazy to move the playing interface into Emacs.

Regardless, if you’re looking for a way to move media playing into Emacs, take a look at Ramírez’s video. It seems like a nice solution.

-1:-- Bending Emacs – Episode 5: Ready Player Mode (Post Irreal)--L0--C0--2025-11-07T15:40:46.000Z

Protesilaos Stavrou: Emacs: modus-themes version 5.1.0

I just published the latest stable release of the Modus themes. The change log entry is reproduced further below. For any questions, you are welcome to contact me. I will now work to apply these same changes to emacs.git, so please wait a little longer for the updates to trickle down to you.


5.1.0 on 2025-11-07

This version fixes a critical bug in the modus-themes-with-colors macro. In short, it was not working as before or was not working at all. Now it should do the right thing.

Thanks to Alexandr Semenov for reporting a relevant bug in issue 170 and for helping me test the results: https://github.com/protesilaos/modus-themes/issues/170.

Thanks to Stéphane Marks for testing some configurations with the latest stable Emacs version as well as with builds from emacs.git. This was done via a private channel and I am sharing this information with permission.

Also thanks to Stefan Monnier for monitoring my commits as I was trying to refactor the modus-themes-with-colors macro. Some comments were posted on the emacs-devel mailing list, as well as a patch that I ended up applying and then reverting (check the commit log for the technicalities): https://lists.gnu.org/archive/html/emacs-devel/2025-11/msg00114.html.

Apologies to everyone for the inconvenience! This was a tricky bug. The good thing is that it compelled me to improve several parts of the code.

This version also includes a clarification in the manual about building a theme on top of Modus:

In short, it mentions that a theme exists in an appropriately named file that is part of the custom-theme-load-path. Thanks to Ashton Wiersdorf for asking a related question in issue 171: https://github.com/protesilaos/modus-themes/issues/171.

-1:-- Emacs: modus-themes version 5.1.0 (Post Protesilaos Stavrou)--L0--C0--2025-11-07T00:00:00.000Z

Irreal: A Toolbar For Edebug

If you write in Elisp, Edebug, a source level debugger for Elisp, can be a real help in debugging your code. The problem is that it’s fairly hard to use and has no UI to speak of other than opaque command keybindings.

Charles Choi has long been bothered by this and has tried to fix it. His first thought was to provide transient menus for the commands but the transient menus interacted badly with the Edebug windows. Then he had an Epiphany: what Edebug needs is a toolbar. That would be in accord with the way most other debuggers work. Even when there are command shortcuts, the toolbar aids in learning and discovery.

As much as I hate using the mouse and toolbars, I have to admit that Choi has a point. I, for one, don’t need Edebug often enough to internalize the command shortcuts or even what’s possible. A toolbar can really help with that. Take a look at Choi’s post to see a screenshot of his toolbar in action.

Choi says that his toolbar is still a work in progress and lists several caveats. One of those is a bug in the NS variant of Emacs, which will, presumably, be fixed in an incoming release; bug reports have already been filed. Another problem is the licensing of the symbol fonts used in the toolbar: they are not GPLv3 compliant. There are some other nits, as well but nothing that should preclude you from trying it out.

Choi is still thinking of it as a proof of concept but if it helps you debug your Elisp code, there’s no reason not to give it a try. If you discover issues, let Choi know.

-1:-- A Toolbar For Edebug (Post Irreal)--L0--C0--2025-11-06T15:27:44.000Z

Paul Jorgensen: OS Abstraction with Emacs

It’s been a while since I blogged Emacs. Let’s jump in.

Brief preamble

I’m pursuing my Master’s Degree in Cybersecurity. I’m working at WUTC 88.1 FM in Chattanooga, Tenn. And I function in this world. While I do some coding, most of what I use Emacs for is system administration, documentation, writing, and reading.

This means –among other things –that I am multi-platform: MacOS, Windows 10/11, Fedora Linux (mostly), iOS/iPadOS/WatchOS, and a wee dram of Android where once I was wholly in the  ecosystem.

How to tackle the non-mobile platforms? Emacs. For mobile? Read and find out.

I need to be effective in whatever platform. That means I need functions that perform tasks in expected ways wherever I am as much as possible.

※ My config started with GitHub – pprevos/emacs-writing-studio: Emacs configuration for authors who re…, thus the references to ews.el.

Keyboard and interface

See my previous posts on the topic. I created a w32.el config that matches.

Name: w32.el.

;;; w32.el --- My Emacs Writing Studio init -*- lexical-binding: t; -*-
;; ╭──────────────────────────────────────────────────────────────────────╮
;; │ Windows config for an Emacs frame                                    │
;; ╰──────────────────────────────────────────────────────────────────────╯
;; Time-stamp:
;;
;; Copyright (C) 2024-2025 Paul R. Jorgensen

;; Author: Paul R. Jorgensen <paul@prjorgensen.com>
;; Maintainer: Paul R. Jorgensen <paul@prjorgensen.com>
;; 
;; This file is NOT part of GNU Emacs.
;;
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
;;
;; Based off of the Emacs Writing Studio init file:
;;    https://lucidmanager.org/tags/emacs, tangled from:
;;    documents/ews-book/99-appendix.org
;;
;; Check https://batsov.com/articles/2025/04/17/using-use-package-the-right-way/
;;    for why this is set up this way
;;
;;; Code:

(use-package emacs
  :bind
  ("C-s-SPC"   . nil                        ) ; blocked by Alfred for me; ns-do-show-character-palette in NS port
  ("M-s-h"     . nil                        ) ; ns-do-hide-others in ns port
  ("s-&"       . kill-current-buffer        )
  ("s-'"       . next-window-any-frame      )
  ("s-'"       . other-frame                )
  ("s-,"       . customize                  )
  ("s-0"       . text-scale-reset           )
  ("s-:"       . ispell                     )
  ("s-<"       . text-scale-decrease        )
  ("s-<down>"  . end-of-buffer              )
  ("s-<left>"  . backward-sentence          ) ; move-beginning-of-line in ns port
  ("s-<right>" . forward-sentence           ) ; move-end-of-line in ns port
  ("s-<up>"    . beginning-of-buffer        )
  ("s->"       . text-scale-increase        )
  ("s-?"       . info                       ) ; conflicts w/ MacOS
  ("s-C"       . nil                        ) ; conflicts w/ Named Keyboard Switcher; ns-popup-color-panel in ns port
  ("s-D"       . dired                      )
  ("s-E"       . edit-abbrevs               )
  ("s-H"       . nil                        ) ; ns-do-hide-others in ns port
  ("s-L"       . shell-command              )
  ("s-M"       . manual-entry               )
  ("s-S"       . write-file                 ) ; ns-write-file-using-panel in ns port
  ("s-Z"       . redo                       )
  ("s-a"       . mark-whole-buffer          )
  ("s-c"       . my-smart-copy-dwim         ) ; ns-copy-including-secondary in ns port
  ("s-d"       . isearch-repeat-backward    ) ; isearch-repeat-backward in ns port
  ("s-e"       . isearch-yank-kill          ) ; blocked by my Keyboard Maestro macro top open Finder window
  ("s-f"       . consult-line-multi         ) ; isearch-forward in ns port
  ("s-g"       . er-keyboard-quit           )
  ("s-h"       . nil                        ) ; ns-do-hide-emacs in ns port
  ("s-j"       . exchange-point-and-mark    )
  ("s-k"       . kill-current-buffer        ) ; Xah has a better function for this
  ("s-l"       . goto-line                  )
  ("s-m"       . iconify-frame              )
  ("s-n"       . make-frame                 )
  ("s-o"       . my-open-file-dialog        ) ; ns-open-file-using-panel in ns port
  ("s-p"       . print-buffer               ) ; conflicts w/ MacOS print
  ("s-Q"       . save-buffers-kill-emacs    ) ; TODO make this safer
  ("s-q"       . restart-emacs              ) ; this saves all buffers and restarts
  ("s-s"       . save-buffer                )
  ("s-t"       . menu-set-font              )
  ("s-u"       . revert-buffer              )
  ("s-v"       . xah-paste-or-paste-previous) ; yank in ns port
  ("s-w"       . xah-close-current-buffer   ) ; delete-frame in ns port
  ("s-x"       . my-smart-cut-dwim          )
  ("s-y"       . nil                        ) ; ns-paste-secondary on ns port
  ("s-z"       . undo                       )
  ("s-|"       . shell-command-on-region    ) ; shell-command-on-region in ns port
  ("s-~"       . previous-frame             )
  :init
  (setq
   w32-alt-is-meta nil
   w32-apps-modifier 'hyper
   w32-enable-caps-lock nil
   w32-lwindow-modifier 'super
   w32-pass-alt-to-system nil
   w32-pass-apps-to-system nil
   w32-pass-lwindow-to-system nil
   )
  (w32-register-hot-key [s-])
  (setq
   w32-rwindow-modifier 'super		; this needs to remain after `w32-register-hot-key'
   )
  :demand t
  :ensure nil
  )

;; Shell
;; http://xahlee.info/emacs/emacs/emacs_powershell.html
(when (eq system-type 'windows-nt)
  (let ((xlist
         '(
          "~/AppData/Local/Microsoft/WindowsApps/pwsh.exe"
          "C:/Windows/System32/WindowsPowerShell/v1.0/powershell.exe"
          ))
        xfound)
    (setq xfound (seq-some (lambda (x) (if (file-exists-p x) x nil)) xlist))
    (when xfound (setq explicit-shell-file-name xfound))))

Keen observers will note a definitive  bend to the [s]uper keybindings.

However, since Win10/11 and Linux DEs tend to expect keyboard layouts to resemble something like [Control] [super] [Alt] [space] [Alt] [super] … [Control]. I’m changing my  machines to match & retraining my brain to accommodate.

For instances when I need to use the system file picker, I use this code:

Name: ews.el.

(defun my-open-file-dialog ()
  "Open the file dialog with custom settings.

URL: https://christiantietze.de/posts/2022/12/use-file-open-dialog-for-file-actions/
Created: 2022-12-01
Updated: 2025-11-03"
  (interactive)
  (let ((last-nonmenu-event nil)
        (use-dialog-box t)
        (use-file-dialog t))
    (call-interactively #'find-file)))

;; You can then bind this function to a key if desired
;; (global-set-key (kbd "C-x C-f") 'my-open-file-dialog)  ; Example key binding

Pandoc

I installed with homebrew on Mac and the Pandoc installer for Win32. I found useful advice here: My Org+Pandoc Workflow including how to set up the associated files.

Name: init.el.

(use-package pandoc)

(use-package ox-pandoc
  :after pandoc
  )
Name: w32.el.

(use-package pandoc-mode
  :after pandoc
  :init
  (setopt
   pandoc-binary "C:/Progra~1/Pandoc/pandoc.exe"
   pandoc-data-dir "plrjorg/config/pandoc/"
   )
  )
Name: ews.el.

(defun my/export-to-docx ()
  "Output to docx using pandoc-mode

URL: https://ismailefe.org/blog/my_org_pandoc_workflow/index.html
Created:2024-03-29
Updated: 2025-11-04"
  (interactive)
  (pandoc-mode)
  (execute-kbd-macro (kbd "C-c / O W d b b r"))
  (setq pandoc-mode nil)
  )

Markdown

Several of the tools at work support markdown, so I need to too.

Name: init.el.

(use-package markdown-mode
  :bind
  (:map markdown-mode-map
        ("C-c C-e"  . markdown-export-and-preview)
        ("s-<tab>"  . completion-at-point        )
        ("s-="      . cc/emphasize-verbatim      )
        ("s-C"      . cc/emphasize-code          )
        ("s-_"      . cc/emphasize-underline     )
        ("s-b"      . cc/emphasize-bold          )
        ("s-e"      . cc/emphasize-dwim          )
        ("s-i"      . cc/emphasize-italic        )
        ("s-s"      . cc/emphasize-strike-through)
        )
  :custom
  (markdown-command "pandoc")
  :hook
  (markdown-mode . pandoc-mode)
  :mode
  ("README\\.md\\'" . gfm-mode)
  )

(use-package ob-markdown
  :vc (ob-markdown :url "https://github.com/tnoda/ob-markdown.git")
  )

(use-package denote-markdown
  :after (denote markdown-mode)
  )

I want to align markdown-mode keybindings with my org-mode ones for equivalent functions. That’s a process.

LibreOffice for exporting

This is as described on the tin: dealing with Office files is easier with LibreOffice installed. Standard OS installation.

Fonts & displays

This revelation made things look good as I jump platforms. I put this in my early-init.el.

Name: early-init.el.

;; Set up the display for proper font scaling
;; https://vxlabs.com/2023/12/09/charls-super-hacky-but-often-working-automatic-emacs-font-size-setting/
;;
;; The main goal is to get the physical / apparent size of the font, in millimetres, to be more similar across all displays and display systems (Different screens across macOS, Windows with and without display scaling, WSL). This sounds like it should be easy, but setting font point size to the same number is in fact interpreted differently on various display systems.

;; Some noteworthy and maybe educational aspects:

;;     `cpb-get-windows-display-scale' uses powershell on Windows to determine the current display scale, e.g. 125% should yield 1.25, in order to determine the effective (scaled) resolution on that platform. The problem is that Emacs reports raw resolution (not scaled), but setting font size works in the scaled space.
;;     `get-monitor-width-mm' uses awk to parse out the physical display width from the weston.log file, because on WSL, the reported physical widhth (in mm) is hardcoded to 96 DPI. Doh.

(defun get-mon-attr (which)
  (cdr (assoc which (car (display-monitor-attributes-list)))))

(defun cpb-get-windows-display-scale ()
  "Use powershell to get the HiDPI display scale as a floating point number."
  (let ((output-buffer (generate-new-buffer "output-buffer")))
    (unwind-protect
        (progn
          ;; powershell to get scaling: https://unix.stackexchange.com/a/713831/32868
          (call-process "powershell.exe" nil output-buffer nil "-NoProfile" "-Command" "Add-Type -AssemblyName System.Windows.Forms; [int](Get-CimInstance -ClassName Win32_VideoController)[0].CurrentVerticalResolution / [int][System.Windows.Forms.SystemInformation]::VirtualScreen.Height")
          (with-current-buffer output-buffer
            (string-to-number (string-replace "," "." (string-trim (buffer-string))))))
      (kill-buffer output-buffer))))

(defun get-monitor-width-mm ()
  (if (getenv "WSL_DISTRO_NAME")
      ;; under WSLg 2021-01-21, physical dimensions are not correctly reported anywhere but weston.log,
      ;; (I hear this is a wayland issue, not just wslg)
      ;; so we use good old awk to get the last occurrence in the log file
      (let* ((awk-dims (shell-command-to-string "awk 'match($0, /physicalWidth:([0-9]+), physicalHeight:([0-9]+)/,a) {width=a[1];height=a[2]} END {print width \",\" height}' /mnt/wslg/weston.log"))
             (splitd (split-string awk-dims ","))
             (width-mm (string-to-number (car splitd))))
        width-mm)
    ;; on other systems, we use whatever Emacs thinks it is
    (car (get-mon-attr 'mm-size))))

(setq monitor-width (get-monitor-width-mm))

(if monitor-width
    (progn
      (setq monitor-hpix (nth 2 (get-mon-attr 'geometry)))
      ;; estimate *effective* PPI (i.e. taking into account scaling / super-sampling)
      ;; the higher the PPI, the more font-pts we need to get characters that are big enough
      ;; - on macOS, it reports the effective PPI (taking into account scaling) already
      ;; - on native Windows, it reports the raw resolution, so we divide by the display scaling to get effective
      ;;   important because font size setting is via effective
      ;; - on WSL it reports native, but font size setting is also native and not scaled, so it works like it should
      (setq display-scale (if (eq system-type 'windows-nt) (cpb-get-windows-display-scale) 1.0))
      (setq ppi-est (/ monitor-hpix display-scale (/ monitor-width 25.4)))

      ;; thinkpad 14" at 100%: (/ 1920 (/ 344 25.4)) => 141.767 -> 140 pts
      ;; 4K at 100% because mac: 3840x => 139
      ;; m1 mba built-in display: (/ 1440.0 (/ 286 25.4)) => 127.88
      ;; 4K at 125%: (/ 3072.0 (/ 697 25.4)) =>  111.949
      ;; - with wslg 1.0.32, geometry now returns the full, unscaled resolution
      ;;   so we get ppi-est 139 even with 125% scaling
      ;; 4K with WACKY macOS scaling 3008x1692: => 109.147
      ;; 27" at 2560x1440 is 108.92 -> font size 130 pts looks fine there
      ;; use ppi-est to adjust font points for your eyes
      (setq my-font-pts (cond
                         ((>= ppi-est 139) 160)
                         ((>= ppi-est 109) 140)
                         (t 130))))

  ;; fallback for when we DON'T have monitor-width, e.g. in text mode
  (setq my-font-pts 140)
  )

(set-face-attribute 'default nil :height my-font-pts)

Cloud sync

Mostly I use Nextcloud for syncing all the things: files, calendars, contacts, RSS, and others.

I use Devonthink as my archive. The server version provides a web interface for non- devices.

There is a little bit of iCloud in my config I’m disentangling, but …

Mobile

From the Emacs side of things I rely heavily on beorg on the  mobile devices. It is the glue. This is important for my workflow. It connects Reminders and Calendar with org-mode. Plus it provides alerting on the  devices for my org events.

Because I’m often mobile and often need to pivot contexts quickly and briefly, friction is a significant hurdle. Maintenance, too, poses challenges.

I’m using Notes and Freeform. I export PDFs to get the info into org and Devonthink.

Journelly goes in and out of the mix, but I think I’ll put it back in as my commonplace book. I’ve tried Notes for this but there are too many steps to append to a note.

As for Android, orgzly-revived seems the best of a paltry selection of apps. For as little as I’m on Android, it works fine. And yes, I know one can run the Emacs port. I chose not to do so.

Epilog

Sharp eyed observers will note I did not talk much about Fedora Linux. My laptop has Omarchy on it right now. Soon I’ll wipe it. Stay tuned.

-1:-- OS Abstraction with Emacs (Post Paul Jorgensen)--L0--C0--2025-11-06T14:10:00.000Z

Irreal: Watts Martin On Everything In Emacs

Serendipitously, my old pal Watts Martin posted his thoughts on everything in Emacs at about the same time that I did. Martin says that before he got into Emacs, he considered this “profoundly weird” but now he’s beginning to see the point.

His sticking point is one I understand and also had to overcome. He, like me, lives in the Apple ecosystem which means that Emacs is available only on his Macs not on his iPhone or iPad. Of course, that’s pretty much true of the Android ecosystem as well. Yes, I know about the Emacs port to Android but, really, do you want to use Emacs on your phone? What would be ideal was if Emacs were available on iPads and Android tablets. That’s theoretically possible on Android tablets but Apple has a firm “no interpreters” rule for iOS apps.

In any event, Emacs is pretty much restricted to our laptop or desktop computers. My main area of contention is my RSS feed, which is effectively restricted to Emacs. I don’t consider that a big problem—especially considering the excellent Elfeed app—but some might. Note taking is covered nicely by the wonderful Journelly but for messaging I’m still effectively restricted to Messages. Email is not a problem. I can read and write Email in Emacs but I can also use any of the Apple mail apps. They all deal with Apple email. As Old El Paso asked, why not both?

The big area is, of course, browsing. Yes, it’s theoretically possible to use Emacs for browsing but as Martin says, “the options for doing so range from bad to bad”. So for now, all but the most rabid Emacs users are consigned to using Emacs and the browser.

Martin, of course, is doomed. He’s already allowing that he may try moving email into Emacs. Once he even considers that, he’s already stepped into the quicksand and there’s no escape. Before long he’ll be wondering why the heck he can’t browse from within Emacs.

-1:-- Watts Martin On Everything In Emacs (Post Irreal)--L0--C0--2025-11-05T15:48:16.000Z

Ruslan Bekenev: Emacs: find-file-at-point trick

The story

Sometimes I hover over a file path in my terminal emulator (in Emacs of course) and type
M-x find-file-at-point. It’s nice command and it works reliably.

I don’t want to type it though. I want Emacs to detect a file path at point.

And there is a built in package for this. Just add this line to your init.el and it should work.

(ffap-bindings)

This makes C-x C-f keybinding to automatically detect a file path at point. Cool!

The twist

Unfortunately it was so much worse than what I’ve expected.

It does detect file path at point so reliably and so often (there are lots of file paths in my terminal output usually)
that almost 80% of time when I press C-x C-f my minibuffer is already pre-filled with the path my cursor happened to be on, which I didn’t need. I wanted it to be clean so I could type a file path there by myself.

I noticed that using ffap package adds a bit of cognitive overload for my workflow. I have to always think about where my cursor is before I press C-x C-f.

I decicded to write my own function that should check for current-prefix-arg and call find-file or find-file-at-point accordingly but just before that I decided to read some docs.

RTFM

Something that I don’t think I’ve ever done is C-h f find-file.

I learned this keybinding early on in my Emacs journey and never needed to read a documentation for it.

But if I read it, it says something about M-n keybinding that uses functions defined in file-name-at-point-functions variable. One of them, by default, is ffap-guess-file-name-at-point.

So having my cursor at a file path, I can type C-x C-f get my regular find-file behavior and then I can just press M-n and the minibuffer will be pre-filled with the file path at point.
^here is how small this blog post could be lol

Perfection.

-1:-- Emacs: find-file-at-point trick (Post Ruslan Bekenev)--L0--C0--2025-11-05T05:29:36.000Z

Alvaro Ramirez: Bending Emacs - Episode 5: Ready Player Mode

I'm now a bit over a month into my Emacs video-making journey. Today I bring a new episode.

Bending Emacs Episode 5: Ready Player Mode

Having migrated to mostly playing offline music, in this episode I show how to use Ready Player Mode (a package I built) for this purpose.

This is what my Ready Player configuration mostly looks like:

(use-package ready-player
  :ensure t
  :custom
  (ready-player-my-media-collection-location "~/Music/Music/Media.localized/Music")
  :config
  (ready-player-mode +1))

On macOS, I have one additional bit to tweak button icons to use SF Symbols. You'll need to tweak your fonts too.

(set-fontset-font t nil "SF Pro Display" nil 'append)
(ready-player-macos-use-sf-symbols)

On a related blog post, I gave a tour of Ready Player Mode.

In the video, I also mentioned dired buffers are at the heard of Ready Player. My dired abstraction post shows how to programmatically craft a valid dired buffer. Spoiler alert, it's pretty simple:

(let ((default-directory "/absolute/path/to/Music/George Benson"))
  (dired '("*My fancy m3u list*"
           "Body Talk/01 Dance.mp3"
           "Body Talk/02 When Love Has Grown.mp3"
           "Body Talk/03 Plum.mp3"
           "Original Album Classics/1-01 So What.mp3"
           "Original Album Classics/1-02 The Gentle Rain (From the Film, _The Gentle Rain_).mp3"
           "Original Album Classics/1-03 All Clear.mp3"
           "The Shape Of Things To Come/01 Footin' It.mp3"
           "The Shape Of Things To Come/02 Face It Boy It's Over.mp3"
           "The Shape Of Things To Come/03 Shape Of Things To Come.mp3")))

Hope you enjoyed the video!

Want more videos?

Liked the video? Please let me know. Got feedback? Leave me some comments.

Please go like my video, share with others, and subscribe to my channel.

If there's enough interest, I'll continue making more videos!

Make it all sustainable

Enjoying this content or my projects? I am an indie dev. Help make it sustainable by ✨sponsoring

Need a blog? I can help with that. Maybe buy my iOS apps too ;)

-1:-- Bending Emacs - Episode 5: Ready Player Mode (Post Alvaro Ramirez)--L0--C0--2025-11-05T00:00:00.000Z

Irreal: Time-zones Is Now On Melpa

A couple of weeks ago, I wrote about Álvaro Ramírez’s time-zones package. It’s a package that expands on the built in world clock function by allowing cities to be added and deleted on the fly and by allowing the target time to be adjusted forward or backward.

When I wrote about it, it had just been released and was not yet on Melpa. Now, thankfully, Ramírez has added it to Melpa and made some enhancements, such as implementing DST and UTC. The original Irreal post got a couple of comments from people who have installed it and they seem happy.

Ramírez is an independent developer and provides apps such as time-zones as a public service. You can download and use it for free but it’s also important to support his efforts. The best way of doing this, I think, is by buying one or more of his paid apps such as Journelly, which I’ve written about many times. I use it constantly, several times a day and, at this point, couldn’t live without it. You’ll be helping Ramírez and yourself by getting a copy. If you don’t want to buy one of his apps, you can become a sponser.

-1:-- Time-zones Is Now On Melpa (Post Irreal)--L0--C0--2025-11-04T15:36:07.000Z

Alvaro Ramirez: agent-shell 0.17 improvements + MELPA

While it's only been a few weeks since the last agent-shell post, there are plenty of new updates to share.

What's agent-shell again? A native Emacs shell to interact with any LLM agent powered by ACP (Agent Client Protocol).

Thank you sponsors

Before getting to the latest and greatest, I'd like to say thank you to new and existing sponsors backing my projects.

While the work going in remains largely unsustainable, your contributions are indeed helping me get closer to sustainability. Thank you!

If you benefit from my content and projects, please consider sponsoring to make the work sustainable.

More productive at work?

Work paying for your LLM tokens and other tools? Why not get your employer to sponsor agent-shell also?

MELPA

Now on to the very first update… Both agent-shell and acp.el are now available on MELPA. As such, agent-shell installation now boils down to:

(use-package agent-shell :ensure t)

New providers

OpenCode and Qwen Code are two of the latest agents to join agent-shell. Both accessible via M-x agent-shell and M-x agent-shell-new-shell through the agent picker, but also directly from M-x agent-shell-opencode-start-agent and M-x agent-shell-qwen-start.

Send files - Thanks to Ian Davidson

Adding files as context has seen quite a few improvements in different shapes. Thank you Ian Davidson for contributing embedded context support.

Send screenshots

Invoke M-x agent-shell-send-screenshot to take a screenshot and automatically send it over to agent-shell.

Activity Indicator

A little side-note, did you notice the activity indicator in the header bar? Yep. That's new too.

@ completion (experimental)

While @ file completion remains experimental, you can enable via:

(setq agent-shell-file-completion-enabled t)

Send files or regions

From any file you can now invoke M-x agent-shell-send-file to send the current file to agent-shell. If region is selected, region information is sent also. Fancy sending a different file other than current one? Invoke M-x agent-shell-send-file with C-u prefix, or just use M-x agent-shell-send-other-file.

Send dired files

M-x agent-shell-send-file, also operates on dired files (selection or region), DWIM style ;-)

Shorter paths in titles

You may have noticed paths in section titles are no longer displayed as absolute paths. We're shortening those relative to project roots.

Shell creation / handling

While you can invoke M-x agent-shell with C-u prefix to create new shells, M-x agent-shell-new-shell is now available (and more discoverable than C-u).

Cancelling sessions

Cancelling prompt sessions (via C-c C-c) is much more reliable now. If you experienced a shell getting stuck after cancelling a session, that's because we were missing part of the protocol implementation. This is now implemented.

Shell commands

Use the new M-x agent-shell-insert-shell-command-output to automatically insert shell (ie. bash) command output.

Markdown transcripts (experimental) - Thanks to Elle Najt

Initial work for automatically saving markdown transcripts is now in place. We're still iterating on it, but if keen to try things out, you can enable as follows:

(setq agent-shell--transcript-file-path-function #'agent-shell--default-transcript-file-path)

Configuration

Turn off ASCII welcome banners

(setq agent-shell-show-welcome-message nil)

Turn off graphical header

Text header

(setq agent-shell-header-style 'text)

No header

(setq agent-shell-header-style nil)

Inline display of historical changes - Thanks to Elle Najt

Applied changes are now displayed inline.

Session mode - Thanks to Elle Najt

The new M-x agent-shell-cycle-session-mode and M-x agent-shell-set-session-mode can now be used to change the session mode.

Agent capabilities

You can now find out what capabilities and session modes are supported by your agent. Expand either of the two sections.

Accepting/rejecting changes from diff buffer

Tired of pressing q and y to accept changes from the diff buffer? Now just press y from the diff viewer to accept all hunks.

Same goes for rejecting. No more q and n. Now just press C-c C-c from the diff buffer.

Transient menu

We get a new basic transient menu. Currently available via M-x agent-shell-help-menu.

Contributions

We got lots of awesome pull requests from wonderful folks. Thank you for your contributions!

  • Arthur Heymans: Add a Package-Requires header (PR).
  • Elle Najt: Execute commands in devcontainer (PR).
  • Elle Najt: Fix Write tool diff preview for new files (PR).
  • Elle Najt: Inline display of historical changes (PR).
  • Elle Najt: Live Markdown transcripts (PR).
  • Elle Najt: Prompt session mode cycling and modeline display (PR).
  • Fritz Grabo: Devcontainer fallback workspace (PR).
  • Guilherme Pires: Codex subscription auth (PR).
  • Hordur Freyr Yngvason: Make qwen authentication optional (PR).
  • Ian Davidson: Embedded context support (PR).
  • Julian Hirn: Fix quick-diff window restoration for full-screen (PR).
  • Ruslan Kamashev: Hide header line altogether (PR).
  • festive-onion: Show Planning mode more reliably (PR).

Lots of other work ❤️😅

Beyond what's been showcased here, much love and effort's been poured into polishing the agent-shell experience. Interested in the nitty-gritty? Have a look through the 173 commits since the last blog post.

Support this work

If agent-shell or acp.el are useful to you, please consider sponsoring its development. LLM tokens aren't free, and neither is the time dedicated to building this stuff ;-)

-1:-- agent-shell 0.17 improvements + MELPA (Post Alvaro Ramirez)--L0--C0--2025-11-04T00:00:00.000Z

Sacha Chua: 2025-11-03 Emacs news

The Emacs Carnival blog theme for November is An Ode to Org Babel. Check out last month's posts about maintenance!

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

View org source for this post

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

-1:-- 2025-11-03 Emacs news (Post Sacha Chua)--L0--C0--2025-11-03T23:21:39.000Z

Charles Choi: Prototyping a Toolbar UI for Edebug

About a year and a half ago I delved into understanding Edebug ((elisp) Edebug), the built-in debugger for Emacs Lisp (Elisp), as I was to give a presentation on it at the Emacs SF meetup. For new users, Edebug can be bewildering as it forces them to know beforehand its many commands and respective keybindings to make good use of it. Because of this complexity, many users writing Elisp often favor simple print-style debugging to avoid ever dealing with Edebug.

My dive into Edebug however left me with the impression that it was more a “kit of parts” in need of a good UI. So I set about to build an Edebug UI with Transient menus. The result of that effort was decidedly mixed. More often than not, window/frame management by Edebug would conflict with Transient. I shelved it.

Working on the toolbar icons for Calle 24, the thought occurred: what about a toolbar for Edebug? The results I think are much more successful, with a number of caveats that I’ll get to later. As far as successes, here’s what I think this toolbar brings:

  • Similarity to conventional IDE debuggers.
  • Avoidance of Edebug window/frame management.
  • Improved discovery of Edebug features.

The screenshot below shows this toolbar in action:

Motivated readers are invited to try this toolbar out using the instructions described in Calle 24 Edebug Support. If you have a prior installation of Calle 24 installed, you should update and re-run the command calle24-install to synchronize with the latest icon set in the v1.1.1 update on MELPA.

Edebug differences from other IDE debuggers

Users new to Edebug but familiar with debuggers for ALGOL-like languages (C, Java, Python, Swift, etc.) should understand that stepping through Elisp code is sexp-based. This distinction is significant when considering stepping into and out of an sexp, which is not the same as a function in ALGOL-like languages. Also, breakpoints can only be set during an Edebug session. If the Edebug-instrumented function is re-evaluated using eval-defun, all prior breakpoints defined for it are lost.

Caveats

Despite my enthusiasm for this toolbar, this should be considered prototype code for the following reasons:

  • There is an existing bug in the NS variant of GNU Emacs 30.1 where repeated rapid pressing of a toolbar button can force Emacs into a state where it is not responsive to GUI input. Bug reports can be found at #76749, #72496.

  • Both NS and GTK variants can only show toolbar icons in a single row.

  • window-tool-bar-mode does not support appearance changes (dark, light mode).

  • The licensing of SF Symbols icons precludes their distribution using a GPLv3 license.

Closing Thoughts

In many ways, building this toolbar has been a “proof of concept” for me in answering the question: can Edebug have a better UI? I think the answer is a resounding yes, so much so that I’ve decided to put it out in public for others to scrutinize. By no means do I consider this “finished product” given the caveats described above. That said, for those folks who decide to give it a try I’d be interested to know your thoughts.

-1:-- Prototyping a Toolbar UI for Edebug (Post Charles Choi)--L0--C0--2025-11-03T21:55:00.000Z

Marcin Borkowski: Beeminder Org timer

Once I wrote about what I called “Org mode burst timer”, another idea occurred to me. That code is good, and may be useful for some people – if it is for you, feel free to use it! But I can do something better for me. Instead of requiring myself to set the burst property manually, I could tie this code to my Emacs Beeminder client. When a clock is started on a beeminded task, it could retrieve the necessary data about the goal associated with the current headline and notify me when I work on it enough.
-1:-- Beeminder Org timer (Post Marcin Borkowski)--L0--C0--2025-11-03T18:57:57.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!