Irreal: macOS Keybindings In Emacs

I periodically publish reminders that

  1. macOS uses some common Emacs editing keystrokes by default, and that
  2. You can do much better by adding other Emacs keystrokes to those that macOS will recognize.

Here’s one such recent reminder. Now Bozhidar Batsov has turned the tables and revealed that Emacs also recognizes many macOS commands1. If you look in ns-win.el you’ll see a rather long list of macOS bindings that Emacs will recognize. You can, for example, save a file with ⌘ Cmd+s or start an incremental search with ⌘ Cmd+f. There’s a surprisingly large number of other such bindings. Take a look at Batsov’s post or ns-win.el for the details.

I didn’t know about any of this except for using ⌘ Cmd+f for isearch. I stumbled on that because I rebound Ctrl+s to swiper-isearch but sometimes wanted to do a regular incremental search. Even then, it didn’t click that Emacs was emulating macOS keybindings.

Other than that—and examples like it that other users may need—I can’t see the point of using those bindings. It seems like just another way of confusing my muscle memory. Of course, as I’ve confessed before, I’m very bad at handling multiple sets of keybindings.

For me, it makes more sense to make Emacs keybinding available to macOS rather than the other way around. Of course, you may disagree and want to standardize on macOS bindings. The great thing is that, as usual, Emacs2 let’s us have it our way.

Footnotes:

1

When it’s running on macOS, of course.

2

Well, in this case, macOS gets some credit for making it easy to use Emacs binding across the OS.

-1:-- macOS Keybindings In Emacs (Post Irreal)--L0--C0--2025-06-05T15:30:40.000Z

Christian Tietze: Emacs Carnival 2025-06: Take Two

To kickstart the Emacs Carnival, and as a hat tip to our recent inspiration, this month’s topic is borrowed from the June IndieWeb Blog Carnival: the topic is “Take Two”, hosted by Nick Simon:

Ever wish for a do-over? “Take two!” (or three, four, etc.) might be shouted by a film director or audio engineer looking to get a somewhat different outcome from a group of actors or musical performers. Would you like a second shot at something that didn’t land?

This is a perfect fit for Emacs users:

We usually don’t nail “it” on our first try – init.el bancruptcy; refactoring hacky Emacs Lisp code; leaving Emacs only to come back englightened much later; running two Emacsens in parallel. There are plenty of possible second takes when it comes to Emacs!

So for this month, our first community blog carnival, I want you to:

  • mediate on “Emacs” and “take two”,
  • blog about it,
  • then send me a link to your blog post.

That’s it! I’ll aggregate submissions for all of June in this post.

Don’t have a blog, yet?

Well, just start one already! :)

It’s the future of the internet!

Blogging is the future, and the future is now!

What’s a Blog Carnival, Again?

This is our first Emacs Carnival, so you may not know the format. A blog carnival is a fun way to tie together a community with shared writing prompts, and marvel at all the creative interpretations of the topic of the month. I’ve provided a couple of interpretations above, but you may think of something else entirely. That’s amazing, roll with it, that’s what makes this fun!

Thanks to Sacha Chua for her post “Working on the plumbing of a small web community” that was part of the May 2025 IndieWeb Carnival, and got me thinking why there’s no Emacs Carnival, yet, and for her encouragement to kickstart this.

For future Carnivals, check out the “Carnival” page on EmacsWiki . It includes instructions, and is our community space to coordinate participants and topic ideas.

Submissions

Comment below or DM/email me with your submission! I’ll collect submissions up to, and including, July 1st (Central European Time), so that every time zone has had a chance to meet the June 30th deadline :)

Bonus: Submit your indie blog post to Nick as well (he really said so)!


Hire me for freelance macOS/iOS work and consulting.

Buy my apps.

Receive new posts via email.

-1:-- Emacs Carnival 2025-06: Take Two (Post Christian Tietze)--L0--C0--2025-06-04T18:25:04.000Z

Irreal: Casual Timezone

Charles Choi has another great addition to his Casual Suite. This time he helps us with the common problem of figuring out what time it is in some other place. As Choi says, the Internet makes it common to communicate regularly with people from all over the world. Even the introverts at Irreal find themselves dealing with this.

Choi says that the most common way of dealing with the problem is with a clock app—which typically show times from all over the world—or just looking it up on the Internet. I do the latter. When I want to communicate with someone in, say, London, I simply search for something along the lines of “what time is it in London?”.

Choi notes that Emacs already has all the machinery to deal with this sort of thing. It just needs to be pulled together into a user accessible package. That’s what Casual Timezone does. It provides a myriad of ways to map the time at one place to the time at another.

At this point, the Casual Suite has so many useful apps that it’s probably best to simply install the whole suite even if there are some that you don’t use. Choi’s use of transient menus makes it easy to use them without having to deal with a bunch of bindings that you seldom use and probably won’t remember. Take a look at his post for an animation of Casual Timezone in action and see it it’s something that might fit your needs.

-1:-- Casual Timezone (Post Irreal)--L0--C0--2025-06-04T16:23:41.000Z

TAONAW - Emacs and Org Mode: Journelly is having me try a new perspective

A couple of people wrote back to me regarding my last post about the challenges I have with Journelly (which, again, don’t really have anything to do with the app itself, but my workflow).

In an Email, HTH let me know that while Syncthing is not officially supported on iOS, there is an app that works and does the job just fine: SyncTrain. I tested it, and it successfully synced my files to my iPhone, iCloud not included. That’s an amazing find.

Meanwhile, I was thinking about how I can better streamline my process of refiling Journelly’s entries to my journal, where they are… archived. Duh! I can simply use org-mode to archive entries into my journal file. All I need to do is define the file I want them to archive into in the file options at the start of the file. Journelly even has an archive feature built in, but since I want to save my entries off the phone, it won’t work for me.

However, I realized I might not want to send my Journelly entries away. Journelly is convenient, and I use it constantly for notes. Having these available on my iPhone (where Journelly has an excellent search feature with tags) and on Emacs on the Mac at the same time is a boon to my productivity, not to mention, it just looks so nice on the phone.

So now I’m considering a different mental approach. Instead of refiling and moving entries away from Journelly, I’m going to try and expand on what I have there later. Some of this I already discussed before: things like meeting entries, for example, can be copied later to my dedicated meeting file, and activities can be copied to my event file, if I feel there’s more to add. The missing piece is expanding on “mind dumps” in Journelly that go into tangents. For that, I want to break the ideas into specific subjects with Denote later. For example, if I write an entry in the morning about Journelly and I’m realizing I’m rambling about the app and have ideas, I can later put these ideas into a “Journelly thoughts” note later with Denote, along with the appropriate keywords and attachments, as needed. This, I think, also covers the concern I have regarding privacy and iCloud, as the Journelly entry will just cover the initial nugget, where I will write some key points which I will later develop in a dedicated note off Apple’s servers.

This is all pretty new and raw in my head, so I’m going to try that out for the rest of the week and see how I feel.

-1:-- Journelly is having me try a new perspective (Post TAONAW - Emacs and Org Mode)--L0--C0--2025-06-04T14:35:00.000Z

James Dyer: Building Your Own Orderless Style Completion in Emacs Lisp

While packages like orderless provide flexible “any word, any order” completion, sometimes you want something lightweight and easy to tweak (well I do anyway). In this post, I’ll show you how to implement a simple orderless-like completion style using only Emacs Lisp, and how to integrate it smoothly into your workflow.

Traditional completion in Emacs often matches prefixes or substrings, but sometimes you want to type a few key parts of a word, in any order, and jump straight to your target. That’s what orderless and similar completion styles allow. But what if you want to write your own, or experiment with the logic?, well I will show you how…

Let’s walk through the logic:

(defun simple-orderless-completion (string table pred point)
  "Enhanced orderless completion with better partial matching."
  (let* ((words (split-string string "[-, ]+"))
         (patterns (mapcar (lambda (word)
                             (concat "\\b.*" (regexp-quote word) ".*"))
                           words))
         (full-regexp (mapconcat 'identity patterns "")))
    (if (string-empty-p string)
        (all-completions "" table pred)
      (cl-remove-if-not
       (lambda (candidate)
         (let ((case-fold-search completion-ignore-case))
           (and (cl-every (lambda (word)
                            (string-match-p
                             (concat "\\b.*" (regexp-quote word))
                             candidate))
                          words)
                t)))
       (all-completions "" table pred)))))

What’s Happening Here?

  • Word Splitting:

    The user’s input (a string) is split into words on spaces, dashes, or commas. This produces a list of “search terms.” This means that, in the minibuffer, the word separator can be any of these characters. I was initially really faffing around and struggling to work out how to insert a space between words in the minibuffer, as it seems to perform some form of completion. However, I eventually figured out that M-SPC actually inserts a space, allowing you to separate words. I use fido-mode, so I’m not sure if this is the same for other minibuffer completion systems.

    After initially adding in the comma separator however I found that I actually prefer it, it is easier to access and I don’t think any keywords, functions e.t.c will typically contain a comma?

  • Pattern Construction:

    For each word, a regex pattern is constructed: \\b.*WORD.*. This means: “find a word boundary, followed by any characters, then the word, then anything else.” This is a bit looser than strict word matching, and you can tune it.

  • Candidate Filtering:

    We generate all possible completions with all-completions and then filter them down. For a candidate to match, all the search terms (words) must appear somewhere, in any order.

  • Case Sensitivity:

    Matching respects completion-ignore-case, so your results will be case-insensitive if you want of course.

Registering and Using the Style

To make Emacs aware of your new completion style, add it to completion-styles-alist:

(add-to-list 'completion-styles-alist
             '(simple-orderless simple-orderless-completion
                                simple-orderless-completion))

Contextual Use: Minibuffer Only

You might not want this style everywhere (which I suspect is likely). For example, in file completion you might prefer strict prefix matching. So, let’s activate it only in the minibuffer:

(defun setup-minibuffer-completion-styles ()
  "Use orderless completion in minibuffer, regular completion elsewhere."
  ;; For minibuffer: use orderless first, then fallback to flex and basic
  (setq-local completion-styles '(basic simple-orderless flex substring)))

;; Hook into minibuffer setup
(add-hook 'minibuffer-setup-hook #'setup-minibuffer-completion-styles)

Tweaking and Extending

  • Pattern Tuning:

    The regexes can be made stricter or looser (e.g., remove \\b for more “fuzzy” matching).

  • Word Separators:

    You can split on other characters if your workflow uses different delimiters.

  • Order of Styles:

    Adjust the order in completion-styles to prefer your custom style over others. I found that if the simple-orderless style was listed first, pressing Tab to bring up the completions buffer doesn’t work, which I like to use sometimes, so that is why basic is first.

Conclusion

With just a handful of lines, you can build your own orderless-like completion style, giving you full control and transparency. This is a great starting point for experimenting with more advanced completion logic, and a good illustration of the power of Emacs’ built-in completion framework!

-1:-- Building Your Own Orderless Style Completion in Emacs Lisp (Post James Dyer)--L0--C0--2025-06-04T08:40:00.000Z

Irreal: Improving Keyboard-quit

Bozhidar Batsov is back with a quick tip that many of you will probably find useful. It’s an improvement to keyboard-quit or, as we all know and love it, Ctrl+g.

One of Batsov’s pet peeves is that keyboard-quit doesn’t function as expected when the minibuffer is active. Happily that and a few other infelicities are easily fixed as he shows in his post. The code that Batsov presents in his post is short. It’s more comment than code yet it does fix the problems that were annoying Batsov.

Here, from the code comments, is what his improved code does:

The DWIM behaviour of this command is as follows:

- When the region is active, disable it.
- When a minibuffer is open, but not focused, close the minibuffer.
- When the Completions buffer is selected, close it.
- In every other case use the regular `keyboard-quit'."

You don’t have to edit Emacs source code. You simply include his function in your init.el and remap Ctrl+g to it. It’s easy to try out his code and if you don’t like it, simply drop back to the default behavior by undoing the key sequence remapping.

-1:-- Improving Keyboard-quit (Post Irreal)--L0--C0--2025-06-03T15:36:25.000Z

Chris Maiorana: Obsidian users curious about Emacs

I just published a video about a Reddit post in which an Obsidian user asks about Emacs: pros and cons, and “aha” moments.

I’m not big on software supremacy type arguments. Whatever tool you decide to use is the best tool for you. I don’t see the point in forever touting one tool over another.

However, I don’t want to downplay the philosophical side of the argument. People who spend time carefully plotting out software choices are no different than laborers in any other field who want to pick the best tool for whatever job they’re doing.

For whatever reason (and I would be curious to get reader comments on this), users of open source tools tend to be more philosophical, I’ve noticed, than users of Windows or Mac products. What I mean by that is, FOSS users tend to value choice, and with that choice there is a greater assumption that you can make wise choices and unwise choices.

Quick example. A Mac user who needs to do some design work has no choice: they have to shell out for a Photoshop license. (They could consider using something like GIMP, but for most users that option would be too beyond the pale, and they might fear the difficulty of integrating a non-standard open source tool within their existing workflow.)

On the other hand, someone who has grown accustomed to open source tools takes on a whole different set of questions. “Can I use GIMP for my project? Of course, but do I need to use it?  Couldn’t I just assemble my graphical items into a script and pipe it into ffmpeg?  What is the best tool for this particular job? What is my ideal result? Should I favor speed or accuracy? Or both?”

Anyway… back to the Obsidian question.

Obsidian is a fine tool. If anyone is purely interested in taking notes and does not use Emacs already, I’d recommend just sticking with Obsidian. It does exactly what you need it to do.

However, if you’re using Emacs already, and you’re comfortable with the interface, I couldn’t think of a good reason to use Obsidian, unless you want to show off a cool hyperlinked graph of your notes and tags.

A few of the other points I mentioned in the video:

  • Emacs provides a superior writing environment.
  • You can code your own note system with Emacs lisp.
  • Emacs’s longevity makes it a safer choice for long term projects.

Whatever tool you decide to use, it’s always best to first take a step back and decide what your ideal outcome would be. Then you can more quickly sample different tools and get an idea of which one will work best for you.

As always, if you enjoy these topics you should subscribe to my newsletter.

The post Obsidian users curious about Emacs appeared first on The Daily Macro.

-1:-- Obsidian users curious about Emacs (Post Chris Maiorana)--L0--C0--2025-06-03T14:08:15.000Z

Emacs Redux: Tree-sitter powered code completion

Tree-sitter has taken the world of programming by a storm. Together with LSP, it’s probably the technology that has influenced the most programming editors and IDEs in the past several years. And now that Emacs 29+ comes with built-in Tree-sitter support I’ve been spending a lot of quality time with it, working on clojure-ts-mode and neocaml-mode.

There’s a lot I’d like to share with you about using Tree-sitter effectively, but today I’ll focus on a different topic. When most people hear about Tree-sitter they think of font-locking (syntax highlighting) and indentation powered by the abstract syntax tree (AST), generated by a Tree-sitter grammar. For a while I’ve also been thinking that the AST data can also be used for simple, yet reasonably accurate, code completion. (within the context of a single code buffer, that is) That’s definitely not nearly as powerful of what you’d normally get from a dedicated tool (e.g. an LSP server), as those usually have project-wide completion capabilities, but it’s pretty sweet given that it’s trivial to implement and doesn’t require any external dependencies.

Below, you’ll find a simple proof of concept for such a completion, in the context of clojure-ts-mode:1

(defvar clojure-ts--completion-query-globals
  (treesit-query-compile 'clojure
                         `((source
                            (list_lit
                             ((sym_lit) @sym
                              (:match ,clojure-ts--variable-definition-symbol-regexp @sym))
                             :anchor [(comment) (meta_lit) (old_meta_lit)] :*
                             :anchor ((sym_lit) @var-candidate)))
                           (source
                            (list_lit
                             ((sym_lit) @sym
                              (:match ,clojure-ts--function-type-regexp @sym))
                             :anchor [(comment) (meta_lit) (old_meta_lit)] :*
                             :anchor ((sym_lit) @fn-candidate))))))

(defconst clojure-ts--completion-annotations
  (list 'var-candidate " Global variable"
        'fn-candidate " Function"))

(defun clojure-ts--completion-annotation-function (candidate)
  (thread-last minibuffer-completion-table
               (alist-get candidate)
               (plist-get clojure-ts--completion-annotations)))

(defun clojure-ts-completion-at-point-function ()
  (when-let* ((bounds (bounds-of-thing-at-point 'symbol))
              (source (treesit-buffer-root-node 'clojure))
              (nodes (treesit-query-capture source clojure-ts--completion-query-globals)))
    (list (car bounds)
          (cdr bounds)
          (thread-last nodes
                 (seq-filter (lambda (item) (not (equal (car item) 'sym))))
                 (seq-map (lambda (item) (cons (treesit-node-text (cdr item) t) (car item)))))
          :exclusive 'no
          :annotation-function #'clojure-ts--completion-annotation-function)))

I hope you’ll agree that the code is both simple and easy to follow (especially if you know a bit about Tree-sitter queries and Emacs’s completion APIs). The meat of the example is clojure-ts--completion-annotation-function, the rest is just completion scaffolding.

And the result looks like this:

clojure-ts-completion.png

Not too shabby for 30 lines of code, right? With a bit more efforts this can be made smarter (e.g. to include local bindings as well), and potentially we can even be consulting all open buffers running clojure-ts-mode to fetch completion data from the as well. (although that’s probably an overkill)

Still, I think that’s an interesting use of Tree-sitter that some of you might find useful. It seems that Nic Ferrier has been playing with this idea recently as well - check out his recent video on the subject here.

In time Tree-sitter will redefine how we’re building Emacs major modes and what they can do.2 It’s still early days and sky is the limit. Exciting times ahead!

That’s all I have for you today. Keep hacking!

P.S. I plan to write more on the topic of Tree-sitter and how to use it in Emacs major modes, but in the mean time you might find some of my development notes useful:

  1. Kudos to Roman Rudakov, who put this prototype together earlier today after a short discussion we had on the topic. 

  2. I can easily imagine things like Tree-sitter based linters or complex refactoring commands. 

-1:-- Tree-sitter powered code completion (Post Emacs Redux)--L0--C0--2025-06-03T13:21:00.000Z

Emacs Redux: Little known macOS keybindings

Today’s article is going to be a bit more weird than usual… mostly because I’ve set to write about one topic, and ended up about writing something completely different in the end… Here we go!

TL;DR Many common macOS keybindings (e.g. Command-s, Command-z, Command-f, etc) work in Emacs. And, of course, it’s well known that macOS uses by default Emacs-like (readline) keybindings everywhere. (e.g. C-a and C-e)

I’m guessing 99% of Emacs users know that the most common ways to start isearch are with isearch-forward (C-s) and isearch-backward (C-r). That’s not the full story, though! While working on my recent isearch article I noticed that out-of-the-box there are two other keybindings for those commands:

  • s-f (isearch-forward)
  • s-F (isearch-backward)

Note: s in this context means Super, which is usually Win in Windows and Command in macOS.

When I saw those I was like “hmm, seems someone wanted to make Emacs a bit more approachable to macOS users coming other editors”. But here things got interesting…

I tried to find out where those extra keybindings were defined, and after a bit of digging I found them in the ns-win.el library1, which defines a ton of macOS-specific keybindings:

;; Here are some Nextstep-like bindings for command key sequences.
(define-key global-map [?\s-,] 'customize)
(define-key global-map [?\s-'] 'next-window-any-frame)
(define-key global-map [?\s-`] 'other-frame)
(define-key global-map [?\s-~] 'ns-prev-frame)
(define-key global-map [?\s--] 'center-line)
(define-key global-map [?\s-:] 'ispell)
(define-key global-map [?\s-?] 'info)
(define-key global-map [?\s-^] 'kill-some-buffers)
(define-key global-map [?\s-&] 'kill-current-buffer)
(define-key global-map [?\s-C] 'ns-popup-color-panel)
(define-key global-map [?\s-D] 'dired)
(define-key global-map [?\s-E] 'edit-abbrevs)
(define-key global-map [?\s-L] 'shell-command)
(define-key global-map [?\s-M] 'manual-entry)
(define-key global-map [?\s-S] 'ns-write-file-using-panel)
(define-key global-map [?\s-a] 'mark-whole-buffer)
(define-key global-map [?\s-c] 'ns-copy-including-secondary)
(define-key global-map [?\s-d] 'isearch-repeat-backward)
(define-key global-map [?\s-e] 'isearch-yank-kill)
(define-key global-map [?\s-f] 'isearch-forward)
(define-key esc-map [?\s-f] 'isearch-forward-regexp)
(define-key minibuffer-local-isearch-map [?\s-f]
  'isearch-forward-exit-minibuffer)
(define-key isearch-mode-map [?\s-f] 'isearch-repeat-forward)
(define-key global-map [?\s-F] 'isearch-backward)
(define-key esc-map [?\s-F] 'isearch-backward-regexp)
(define-key minibuffer-local-isearch-map [?\s-F]
  'isearch-reverse-exit-minibuffer)
(define-key isearch-mode-map [?\s-F] 'isearch-repeat-backward)
(define-key global-map [?\s-g] 'isearch-repeat-forward)
(define-key global-map [?\s-h] 'ns-do-hide-emacs)
(define-key global-map [?\s-H] 'ns-do-hide-others)
(define-key global-map [?\M-\s-h] 'ns-do-hide-others)
(define-key global-map [?\s-j] 'exchange-point-and-mark)
(define-key global-map [?\s-k] 'kill-current-buffer)
(define-key global-map [?\s-l] 'goto-line)
(define-key global-map [?\s-m] 'iconify-frame)
(define-key global-map [?\s-n] 'make-frame)
(define-key global-map [?\s-o] 'ns-open-file-using-panel)
(define-key global-map [?\s-p] 'ns-print-buffer)
(define-key global-map [?\s-q] 'save-buffers-kill-emacs)
(define-key global-map [?\s-s] 'save-buffer)
(define-key global-map [?\s-t] 'menu-set-font)
(define-key global-map [?\s-u] 'revert-buffer)
(define-key global-map [?\s-v] 'yank)
(define-key global-map [?\s-w] 'delete-frame)
(define-key global-map [?\s-x] 'kill-region)
(define-key global-map [?\s-y] 'ns-paste-secondary)
(define-key global-map [?\s-z] 'undo)
(define-key global-map [?\s-+] 'text-scale-adjust)
(define-key global-map [?\s-=] 'text-scale-adjust)
(define-key global-map [?\s--] 'text-scale-adjust)
(define-key global-map [?\s-0] 'text-scale-adjust)
(define-key global-map [?\s-|] 'shell-command-on-region)
(define-key global-map [s-kp-bar] 'shell-command-on-region)
(define-key global-map [?\C-\s- ] 'ns-do-show-character-palette)
(define-key global-map [s-right] 'move-end-of-line)
(define-key global-map [s-left] 'move-beginning-of-line)

(define-key global-map [home] 'beginning-of-buffer)
(define-key global-map [end] 'end-of-buffer)
(define-key global-map [kp-home] 'beginning-of-buffer)
(define-key global-map [kp-end] 'end-of-buffer)
(define-key global-map [kp-prior] 'scroll-down-command)
(define-key global-map [kp-next] 'scroll-up-command)

;; Allow shift-clicks to work similarly to under Nextstep.
(define-key global-map [S-mouse-1] 'mouse-save-then-kill)
(global-unset-key [S-down-mouse-1])

;; Special Nextstep-generated events are converted to function keys.  Here
;; are the bindings for them.  Note, these keys are actually declared in
;; x-setup-function-keys in common-win.
(define-key global-map [ns-power-off] 'save-buffers-kill-emacs)
(define-key global-map [ns-open-file] 'ns-find-file)
(define-key global-map [ns-open-temp-file] [ns-open-file])
(define-key global-map [ns-open-file-line] 'ns-open-file-select-line)
(define-key global-map [ns-spi-service-call] 'ns-spi-service-call)
(define-key global-map [ns-new-frame] 'make-frame)
(define-key global-map [ns-toggle-toolbar] 'ns-toggle-toolbar)
(define-key global-map [ns-show-prefs] '

Some of them look quite convenient (easy to press), so I might add a few to my daily work. I’m shocked I never trying any of the standard macOS keybindings for things like adjusting text size in Emacs. Or perhaps I tried them and then I forgot about them… :D

Still, even though I’m a macOS users (at least for the time being), I doubt I’ll end up using many of them. The reason for this is that I learned Emacs on Linux and I’m extremely used to the default keybindings. Between remembering all of those, and trying to master Vim (as of late), it’s hard to teach this old dog any new tricks. That being sad, I can imagine those keybindings being useful to many other people, especially if they haven’t learned Emacs on Linux 20 years ago.

Tip: Do a M-x find-library RET ns-win to see what else the library has in store for macOS users.

All of this is, of course, made possible by the fact that macOS relies heavily on the Command key which normally isn’t used in Emacs at all. For similar reasons it’s “easier” to copy/paste text from/in your shell on macOS, compared to Linux and Windows, as keybindings like Command + c and Command + v are not used by any shell.

That’s all I have for you today! Keep hacking!

P.S. After writing this article I was really amused that I’ve been using macOS on and off for over 10 years and I never bothered to try whether something like Command-s or Command-z works in Emacs! Oh, well… habits!

  1. Emacs stubbornly keeps refering to macOS by its ancient name NextStep in much of the code and its documentation. 

-1:-- Little known macOS keybindings (Post Emacs Redux)--L0--C0--2025-06-03T06:48:00.000Z

Tim Heaney: Hy PyO3!

Lately, I've been messing with Codelist Tools, a Rust library for working with medical codelists. Among other things, it uses PyO3 to provide bindings that enable its use from Python. I had not tried this before. It's fun! It occurred to me that it should also work from Hy, a Lisp dialect for Python. So, I gave it a try…and it does! Running either of these produces
-1:-- Hy PyO3! (Post Tim Heaney)--L0--C0--2025-06-03T00:00:00.000Z

Irreal: Why Does Emacs Take So Long To Load

Over at the Emacs subreddit, EachDaySameAsLast asks the perennial question: why does Emacs take so long to load. Actually, his question is, “Why do people say Emacs takes so long to load?” He has, he says, been using Emacs since its TECO days and has never, even in the old days, experienced overly long load times. To be sure, his configuration file is relatively short—about 100 lines—but Emacs loads for him in under 2 seconds.

Of course, as many of us have been saying and saying, none of that matters. For almost every user, Emacs shouldn’t be started very often: once a day at most, once every week or month typically.

As usual, the interesting part of the post is the comments. Almost everyone agrees: the load times don’t matter but if you use use-package and the defer option judiciously, your load time can be small too.

I’m beginning to feel as if I’m codependent with those people claiming that Emacs takes too long to load. I should probably just stop writing about it. Of course, it won’t matter. People—many of whom don’t even use Emacs—will keep repeating it.

But let me just repeat, with Batsov, that Emacs load time doesn’t matter. It really doesn’t.

-1:-- Why Does Emacs Take So Long To Load (Post Irreal)--L0--C0--2025-06-02T15:22:38.000Z

Sacha Chua: 2025-06-02 Emacs news

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

View org source for this post

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

-1:-- 2025-06-02 Emacs news (Post Sacha Chua)--L0--C0--2025-06-02T13:19:50.000Z

Charles Choi: Announcing Casual Timezone

Because the Internet, it is a blessing of our time that interacting with people in different time zones is commonplace. In this, the question is often raised: “what time is it there?” This is routinely answered using a clock app or a website.

While Emacs has long had the ability to make time zone calculations, it seemed overdue to have tooling that takes advantage of it.

Announcing Casual Timezone, now available as part of the Casual v2.5.0 update on MELPA.

The following screencast shows Casual Timezone in action, in this case a meeting planner (command: casual-timezone-planner) that compares the hours with your local time zone with that of another.

Casual Timezone also lets you directly ask:

  • “What time is it over there?” (command: casual-timezone-local-time-to-remote)
  • “That time over there, what is it here?” (command: casual-timezone-remote-time-to-local)

Note that at current, Casual Timezone only supports Unix-variant systems as it relies on the tz database. It has been tested on macOS 15.5 and Ubuntu Linux 22.04. Sorry Windows users, but I’m open for a PR for Windows support if a workaround for zoneinfo is available.

Closing Thoughts

With experience, I’ve learned to be humble about working with time APIs. While I’ve done much to ensure the results are accurate, I would not be surprised if there are bugs, especially for a first release. Let me know if you find any.

On reflection, putting Casual Timezone together was relatively easy as it was largely an exercise in integrating different Elisp packages:

  • From Org, the command org-read-date provided the date picker UI.
  • Built-in completion provided the UI for selecting a time zone.
  • vtable provided the table interface for casual-timezone-planner.
  • The table interface was configured as a derived mode to provide mode-specific behavior.
  • The built-in time functions were used for time zone calculations and formatting.
  • Transient provided support for menus.

Gonna call this an Elisp code-reuse success story.

References

-1:-- Announcing Casual Timezone (Post Charles Choi)--L0--C0--2025-06-02T13:00:00.000Z

Emacs Redux: Let’s make keyboard-quit smarter

I’ll be pretty brief today. keyboard-quit (C-g) is one of the most used commands, but unfortunately it’s not very smart. Most annoyingly, it doesn’t work as expected when the minibuffer is active.

Fortunately, fixing such problems (and then some) is trivial in Emacs:

(defun er-keyboard-quit ()
  "Smater version of the built-in `keyboard-quit'.

The generic `keyboard-quit' does not do the expected thing when
the minibuffer is open.  Whereas we want it to close the
minibuffer, even without explicitly focusing it."
  (interactive)
  (if (active-minibuffer-window)
      (if (minibufferp)
          (minibuffer-keyboard-quit)
        (abort-recursive-edit))
    (keyboard-quit)))

I’d suggest to just remap keyboard-quit to our improved version:

(global-set-key [remap keyboard-quit] #'er-keyboard-quit)

There are other ways to tackle this particular issue, of course, and different people might prefer an even more complicated version of the smarter keyboard-quit or one that does fewer things. One of my readers suggested in the comments a similar solution using an advice:

(define-advice keyboard-quit
    (:around (quit) quit-current-context)
  "Quit the current context.

When there is an active minibuffer and we are not inside it close
it.  When we are inside the minibuffer use the regular
`minibuffer-keyboard-quit' which quits any active region before
exiting.  When there is no minibuffer `keyboard-quit' unless we
are defining or executing a macro."
  (if (active-minibuffer-window)
      (if (minibufferp)
          (minibuffer-keyboard-quit)
        (abort-recursive-edit))
    (unless (or defining-kbd-macro
                executing-kbd-macro)
      (funcall-interactively quit))))

This has the benefit of directly modifying the original command, so you don’t really need to rebind anything. On the other hand - advices are arguably a bit more complicated to understand and debug. Personally, I like to replace functions in my own setup with versions that I prefer, as I think this makes the modifications more obvious.

Another option is a similar function from Prot:1

(defun prot/keyboard-quit-dwim ()
  "Do-What-I-Mean behaviour for a general `keyboard-quit'.

The generic `keyboard-quit' does not do the expected thing when
the minibuffer is open.  Whereas we want it to close the
minibuffer, even without explicitly focusing it.

The DWIM behaviour of this command is as follows:

- When the region is active, disable it.
- When a minibuffer is open, but not focused, close the minibuffer.
- When the Completions buffer is selected, close it.
- In every other case use the regular `keyboard-quit'."
  (interactive)
  (cond
   ((region-active-p)
    (keyboard-quit))
   ((derived-mode-p 'completion-list-mode)
    (delete-completion-window))
   ((> (minibuffer-depth) 0)
    (abort-recursive-edit))
   (t
    (keyboard-quit))))

I know this version of the command is quite popular in the wild, as many people follow Prot’s work, but looking at the code of the actual keyboard-quit it seems to me that Prot’s version is more complicated than it needs to be:

;; This executes C-g typed while Emacs is waiting for a command.
;; Quitting out of a program does not go through here;
;; that happens in the maybe_quit function at the C code level.
(defun keyboard-quit ()
  "Signal a `quit' condition.
During execution of Lisp code, this character causes a quit directly.
At top-level, as an editor command, this simply beeps."
  (interactive)
  ;; Avoid adding the region to the window selection.
  (setq saved-region-selection nil)
  (let (select-active-regions)
    (deactivate-mark))
  (if (fboundp 'kmacro-keyboard-quit)
      (kmacro-keyboard-quit))
  (when completion-in-region-mode
    (completion-in-region-mode -1))
  ;; Force the next redisplay cycle to remove the "Def" indicator from
  ;; all the mode lines.
  (if defining-kbd-macro
      (force-mode-line-update t))
  (setq defining-kbd-macro nil)
  (let ((debug-on-quit nil))
    (signal 'quit nil)))

As you can see it already handles things like the selected region and completion in region. But perhaps I’m missing what Prot was trying to achieve with his version.

Which of the three approaches do you prefer? How would you improve er-keyboard-quit-dwim further?

That’s all I have for you today! Keep hacking!

-1:-- Let’s make keyboard-quit smarter (Post Emacs Redux)--L0--C0--2025-06-01T20:39:00.000Z

TAONAW - Emacs and Org Mode: I wish I could use Journelly's new location features, but...

Journelly keeps getting updated with good features. One of the latest features I noticed (I’m not sure if it was part of the latest patch) is that locations tagged with entries can be revisited in iOS Maps from the app. This makes Journelly a good spot to save locations and integrate them with personal memories, to be revisited later on the map. I would like to use this (instead of, say, a saved of locations on Google Maps), but I can’t - for two reasons.

The first one, which I can work around, is that the list of entries on Journelly quickly becomes long, and finding where you were a couple of weeks ago requires some scrolling. While Journelly has a search option, I usually don’t remember the name of the place I’m searching for, which is why I’m searching for it in the first place. Still, I could probably look for who I was with at the time, or even better, use the tagging feature, which was introduced a couple of weeks ago, for, say, “#cafes” to filter down cafes only.

The other issue is more challenging: I don’t keep my notes in Journelly. I keep refiling my entries into my main journal file. That file, while still on my Mac, is not synced with iCloud. Call me paranoid, but I don’t trust Apple’s iCloud with my personal notes along with my pictures throughout the years. As far as I’m concerned, Apple just has a better PR department than Google and Microsoft, and they only care about their users' privacy as long as it’s what looks good in the news. Because of that, I am not comfortable with Journelly being my archive of notes. There could be other options besides iCloud, but as far as I know, they all involve a cloud company somewhere. On Android and macOS, I still use the excellent Syncthing, which doesn’t involve any cloud storage. However, Syncthing doesn’t work on iOS, so I’m out of luck.

Besides these two issues (which have nothing to do with the app), the app is terrific. It’s amazing how polished and responsive it is.

-1:-- I wish I could use Journelly's new location features, but...  (Post TAONAW - Emacs and Org Mode)--L0--C0--2025-06-01T20:13:39.000Z

Irreal: Web Browsing In Emacs

Joar Von Arndt has an interesting post on a subject that many Emacs users obsess about: how to bring Web browser functionality into Emacs. As, I’ve said many times, virtually all my tube time is either in Emacs or Safari. I would, of course, like to get that down to just Emacs. To be sure, I do use some other apps but my time with them is basically in the noise. Almost everything I do on the computer involves Emacs or the browser.

Von Arndt looks at eww, w3m, Xwidgets, and EAF. He discusses the pros and cons of each. He appears to think that eww—with some customization—is the best solution.

My solution is to use Xwidgets for rendering Email posts that need it and for my RSS feed via Elfeed. My email client, mu4e, makes it easy to switch between text and HTML rendered displays. It is, in a way, the best of both worlds. I can read most of my emails in plain text, as the elders decreed, but can switch to an HTML rendered display when I need to.

I use elfeed-webkit to display my RSS feed with Elfeed. It brings up each entry in a browser like display and, of course, can be easily be toggled on and off. It’s a bit fragile, as Von Arndt says, but it easier than invoking the brower for each entry.

The sad news is that there still isn’t a good solution but what solutions there are are getting better. Perhaps we will soon have a way of bringing the final major holdout into the Emacs fold.

-1:-- Web Browsing In Emacs (Post Irreal)--L0--C0--2025-06-01T14:46:41.000Z

Sacha Chua: Working on the plumbing in a small web community

The IndieWeb Carnival prompt for May is small web communities. I've been exploring some thoughts on how a little effort goes a long way to connecting a community. Sometimes I think of it as working on the plumbing so that ideas can flow more smoothly. It feels a little different from the direct contribution of knowledge or ideas. I also want to connect with other people who do this kind of thing.

Emacs is a text editor that has been around since the 1970s. It's highly programmable, so people have come up with all sorts of ways to modify it to do what they want. It's not just for programmers. My favourite examples include novelists and bakers and musicians who use Emacs in unexpected ways. Because Emacs is so flexible, community is important. The source code and documentation don't show all the possible workflows. As people figure things out by themselves and together, more possibilities open up.

I love tweaking Emacs to help me with different things I want to do, and I love learning about how other people use it too. I've been sharing my notes on Emacs on this blog since 2001 or so. In 2015, as I was getting ready to become a parent, I knew I was going to have much less time and focused attention, which meant less time playing with Emacs. Fortunately, around that time, John Wiegley (who was one of the maintainers of Emacs at the time) suggested that it would be helpful if I could keep an eye on community updates and summarize them. This worked well with the fragmentation of my time, since I could still speed-read updates and roughly categorize them.

Text from sketch

Community plumbing

You don't have to fill the pipes all by yourself. Just help things flow.

I want to share some of the things we're doing in the Emacs community so that I can convince you that building plumbing for your community can be fun, easy, and awesome. This is great because enthusiasm spreads.

virtuous cycle

  • Other places: YouTube, Reddit, HN, lobste.rs, Mastodon, PeerTube, mailing lists….
  • Blog aggregator
    • Planet Emacs Life (uses Planet Venus) - update: [2025-05-31 Sat] I wrote my own RSS feed aggregator instead.
  • Newsletter: Emacs News, 1-2 hours a week
    • summarize & group
    • announce calendar events
  • User groups
    • [often use Emacs News to get conversations going]
  • iCal & Org files: Emacs Calendar
  • Conference
    • EmacsConf: < USD 50 hosting costs + donated server + volunteer time

Tips:

  • Make it fun for yourself.
  • Build processes and tools.
  • Let people help

2024-01-31-05

Some more notes on the regular flows built up by this kind of community plumbing:

Daily: Lots of people post on reddit.com/r/emacs and on Mastodon with the #emacs hashtag. I also aggregate Emacs-related blog posts at planet.emacslife.com, taking over from planet.emacsen.org when Tess had DNS issues. There are a number of active channels on YouTube and occasionally some on PeerTube instances as well. I don't need to do much work to keep this flowing, just occasionally adding feeds to the aggregator for planet.emacslife.com.

Weekly: I collect posts from different sources, remove duplicates, combine links talking about the same thing, categorize the links, put them roughly in order, and post Emacs News to a website, an RSS feed, and a mailing list. This takes me maybe 1.5 hours each week. It's one of the highlights of my week. I get to learn about all sorts of cool things.

Weekly seems like a good rhythm for me considering how active the Emacs community is. Daily would be too much time. Monthly would lead to either too long of a post or too much lost in curation, and the conversations would be delayed.

Sometimes I feel a twinge of envy when I check out other people's newsletter posts with commentary or screenshots or synthesis. (So cool!) But hey, I'm still here posting Emacs News after almost ten years, so that's something. =) A long list of categorized links fits the time I've got and the way my mind works, and other people can put their own spin on things.

Monthly: There are a number of Emacs user groups, both virtual and in-person. Quite a few of them use Emacs News to get the discussion rolling or fill in gaps in conversation, which is wonderful.

Some meetups use meet.jit.si, Zoom, or Google Meet, but some are more comfortable on a self-hosted service using free software. I help by running a BigBlueButton web conferencing server that I can now automatically scale up and down on a schedule, so the base cost is about 60 USD/year. Scaling it up for each meetup costs about USD 0.43 for a 6-hour span. It's pretty automated now, which is good because I tend to forget things that are scheduled for specific dates. My schedule still hasn't settled down enough for me to host meetups, but I like to drop by once in a while.

Yearly: EmacsConf is the one big project I like to work on. It's completely online. It's more of a friendly get-together than a formal conference. I have fun trying to fit as many proposed talks as possible into the schedule. We nudge speakers to send us recorded presentations of 5-20 minutes (sometimes longer), although they can share live if they want to. A number of volunteers help us caption the videos. Each presentation is followed by Q&A over web conference, text chat, and/or collaborative document. Other volunteers handle checking in speakers and hosting the Q&A sessions.

It's a lot of fun for surprisingly little money. For the two-day conference itself, the website hosting cost for EmacsConf 2024 was about USD 56 and our setup was able to handle 400 viewers online (107 max simultaneous users in various web conferences).

EmacsConf takes more time. For me, it's about 1.5 hours a day for 4 months, but I think mostly that's because I have so much fun figuring out how to automate things and because I help with the captions. Lots of other people put time into preparing presentations, hosting Q&A, participating, etc. It's worth it, though.

I like doing this because it's a great excuse to nudge people to get cool stuff out of their head and into something they can share with other people, and it helps people connect with other people who are interested in the same things. Some Q&A sessions have run for hours and turned into ongoing collaborations. I like turning videos into captions and searchable text because I still don't have the time/patience to actually watch videos, so it's nice to be able to search. And it's wonderful gathering lots of people into the same virtual room and seeing the kind of enthusiasm and energy they share.

So yeah, community plumbing turns out to be pretty enjoyable. If this resonates with you, maybe you might want to see if your small web community could use a blog aggregator or a newsletter. Doesn't have to be anything fancy. You could start with a list of interesting links you've come across. I'm curious about what other people do in their communities to get ideas flowing!

Related: the community plumbing section of my blog post / livestream braindump.

View org source for this post

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

-1:-- Working on the plumbing in a small web community (Post Sacha Chua)--L0--C0--2025-06-01T03:51:15.000Z

Protesilaos Stavrou: Emacs: spacious-padding version 0.7.0

This is a small release that makes spacious-padding-mode work as intended when used in tandem with the Emacs daemon and subsequent calls to emacsclient -c. I made the function responsible for triggering the “spacious padding” effects work with individual frames and then I responded to issue 33 by Lou Woell about integrating that with the server-after-make-frame-hook: https://github.com/protesilaos/spacious-padding/issues/33.

Additionally, the package now defines two faces that can be used to configure the user option spacious-padding-subtle-mode-line (read its documentation string for all the possible values it accepts).

Here is how they can be set (default value is nil):

(setq spacious-padding-subtle-mode-line
      '( :mode-line-active spacious-padding-subtle-mode-line-active
         :mode-line-inactive spacious-padding-subtle-mode-line-inactive))

Reload the spacious-padding-mode for changes to take effect.

When configured this way and with default styles they make the mode line use a minimalist overline with no background colour. The active mode line has a more noticeable border than the inactive ones. All my themes are designed to support this aesthetic (though themes can style those faces as they see fit).

About Spacious Padding

This package provides a global minor mode to increase the spacing/padding of Emacs windows and frames. The idea is to make editing and reading feel more comfortable. Enable the mode with M-x spacious-padding-mode. Adjust the exact spacing values by modifying the user option spacious-padding-widths.

Inspiration for this package comes from Nicolas Rougier’s impressive designs and Daniel Mendler’s org-modern package.

-1:-- Emacs: spacious-padding version 0.7.0 (Post Protesilaos Stavrou)--L0--C0--2025-06-01T00:00:00.000Z

Tim Heaney: Go to definition in Emacs

Today, I was reading Why Use Structured Errors in Rust Applications? and one of the issues discussed is jumping away from the code you're working on to look at the definition of the error. On the one hand, rust-analyzer makes it really easy to jump to the error, but on the other hand they felt that they sometimes had to do so unnecessarily. In the comments on lobste.rs, matklad mentioned that he recently adopted the habit of splitting the screen first and going to the definition in the split (in Emacs terms, in the other window).
-1:-- Go to definition in Emacs (Post Tim Heaney)--L0--C0--2025-06-01T00:00:00.000Z

Marcin Borkowski: Converting integers to ISO-8601 timestamps

Two weeks ago I wrote about using defcustom​’s :get and :set keywords, allowing the user to set an option containing a Unix timestamp (that is, a number) using an ISO-8601 timestamp. Today I am going to use such an option.
-1:-- Converting integers to ISO-8601 timestamps (Post Marcin Borkowski)--L0--C0--2025-05-31T18:40:14.000Z

Irreal: Adding Timestamped Notes To The LOGBOOK Drawer

Jeff Bradberry has an excellent post on adding timestamped notes to the LOGBOOK drawer in Org files. Most of us are used to using this drawer to record state changes in TODO notes. You can arrange to have the times of the state changes added to the LOGBOOK. You can also arrange to pop up a buffer so that you can add a note to the entry. I do this when the state changes to CANCELLED or WAITING. Sometimes you may want to add a note to a state change that doesn’t normally have one.

That turns out to be easy. You simple add the universal argument to the state change call. If you use the normal Ctrl+c Ctrl+t binding, you would simply use Ctrl+u Ctrl+c Ctrl+t instead when you want to add a note.

Many of you probably already know all this but Bradberry thought it would nice to add arbitrary notes to the drawer as well. That turns out to be easy too. As usual, Emacs has us covered. You simply call org-add-note bound to Ctrl+c Ctrl+z by default.

This post is the seventh in a series on building an Org-mode Workflow. The whole series is worthwhile and you should definitely take a look if you’re an Org user. There are links to the entire series in Bradberry’s post.

-1:-- Adding Timestamped Notes To The LOGBOOK Drawer (Post Irreal)--L0--C0--2025-05-31T15:48:51.000Z

Irreal: 🥩 Red Meat Friday: Load Times Matter?

It seems as if everybody having even a passing acquaintance with Emacs is opining about Emacs load times. That includes Irreal, of course. Most of us take the position that it doesn’t really matter how long it takes Emacs to start because it’s something that happens only rarely.

Every serious person acknowledges that there are exceptions. A (very) few people have to restart Emacs often for various reasons but for the most part the majority of us have no reason to care. Of course, that doesn’t stop some people from caring. And caring a lot.

Over at the Programming subreddit, dormunis1 is proudly announcing that he’s gotten his Zsh load time to under 70 ms. This is down from the apparently normal load time of 0.45 seconds. If you don’t see the problem with this, you should seek help. These times are all below human reaction times so reducing them, while an interesting intellectual challenge, serves no real purpose.

As usual, a lot of the meat is in the comments. Most of the commenters aren’t sympathetic and agree that it’s an optimization without a point. To be sure, learning to do this sort of thing is useful for cases where it does matter. My objection—and that of the other commenters, apparently—is that reducing the load time of Zsh, Emacs, or any other user facing app, by a few milliseconds simply doesn’t matter.

-1:-- 🥩 Red Meat Friday: Load Times Matter? (Post Irreal)--L0--C0--2025-05-30T15:39:12.000Z

Matt Maguire: Plain Text Accounting with Emacs – Part 3

My journey into using Hledger with Emacs to track my share investments continues. Last Time I looked at a way to track shares using a plain text file. Since then I have made some tweaks to my workflow as I gain more experience:

  • naming conventions that support multiple stock brokers
  • booking brokerage fees in a better way to support the Australian tax system.

Naming convention

Over the past month I was not overly impressed with my existing stock broker, which led me to explore other stock brokers that may offer a more reliable service at a cheaper rate. It is expensive to transfer stocks over to a new broker, so I decided to cap further investment at my current broker and instead make any new purchases at a different broker. This meant that I would need an account structure that lets me easily identify which share lots were purchased through which broker.

-1:-- Plain Text Accounting with Emacs – Part 3 (Post Matt Maguire)--L0--C0--2025-05-30T00:00:00.000Z

Irreal: macOS Emacs Tricks

I’ve been writing a lot lately about Álvaro Ramírez’s Journelly, an iOS app that I use constantly everyday. It’s a great app that I recommend for everyone. But Ramírez has been writing apps for Emacs and iOS for a long time. A previous iOS app of his that I used and liked—before Journelly largely replaced it—is scr that sort of implements an Emacs ∗scratch∗ buffer on your iPhone or iPad. I’ve also written extensively about his dwim-shell-command package that provides all sorts of command line shortcuts from within Emacs.

All of this is by way of an introduction to Ramírez’s recent post on tricks for using Emacs on macOS. It’s a long post with a plethora of strategies for using Emacs on Macs. He starts off by mentioning that he uses Emacs Plus—available from Homebrew—rather than compiling it from source, as he used to do. I still compile from source but on my next machine I may take the easy route and use Emacs Plus too.

Another thing he mentions is a point I often make: Although he was a GNU/Linux user for many years, he now works primary on macOS but this doesn’t matter because he does almost everything in Emacs or his browser so the he can get away with being pretty much OS agnostic. The true believers will gasp in horror but it’s a truth that many of us have discovered.

As for the tips, they are too numerous to list here. Most people probably won’t like all of them but I’d be surprised if anyone couldn’t find something useful in the post. For my part, I really liked his configuration for long press for accents and Plain Org for iOS. I expect to implement both of these in the near future.

If you use Emacs on macOS you should definitely take a look at Ramírez’s post. You’re sure to find something useful.

-1:-- macOS Emacs Tricks (Post Irreal)--L0--C0--2025-05-29T15:34:12.000Z

Tim Heaney: R programming in Emacs

If you want to do statistical calculations with your computer, you probably want to use some sort of package to help you. When I was in school, we used Minitab (a "mini" version of OMNITAB— now there's a great name!), but I guess most statisticians used either S or SAS at the time. Later, R came along as an alternative to S. I may want to use extendr to access a Rust library from R, so I thought I would start by installing R on my Debian desktop.
-1:-- R programming in Emacs (Post Tim Heaney)--L0--C0--2025-05-29T00:00:00.000Z

Irreal: GitHub As A Notebook

I like GitHub well enough; I link to it often and even have an account but I would never consider using it for anything but public files that I had replicated on my own machine. I’ve been over the reasons for that many times. The most important reason is that you should never commit your only copy of any data you care about to a third party computer. Once you do, a clock starts ticking down to the time that you will lose your data. You never know how much time is left on the clock but you can be sure that it will eventually reach 0.
The second reason is that any site that hosts a lot of data is an attractive target for criminals and your data could be compromised. Here’s the latest GitHub exploit. That’s why I say I would only use GitHub for public data.

All of this is by way of introduction to this post from Simon Willison. In it Willison posits that GitHub is (almost) the perfect notebook. What follows is a list of features that could easily be a description of Org mode. Read it and see if you don’t agree.

The only reason for Willison’s “almost” is the lack of synchronized offline support. I submit that Journelly goes a long ways towards meeting that concern for Org mode. I’ve previously described it as a front end for Org and although it doesn’t expose all your Org files to your remote device it gets you a long way.

Given all that, it’s clear to me that Emacs and Org mode is a much better notebook than GitHub could hope to be. Your data is safer both from criminals and from being disappeared for some reason by a third party provider. My only question is why do I have to keep repeating this.

-1:-- GitHub As A Notebook (Post Irreal)--L0--C0--2025-05-28T15:21:04.000Z

James Dyer: Bank Buddy - Your Financial Analysis Companion for Emacs!

I created a new package!, here are the details:

Bank Buddy is an Emacs package that provides financial analysis and reporting capabilities for your bank statements. It processes CSV bank statement data, categorizes transactions using customizable patterns, and generates detailed reports in Org-mode format.

It does not depend on any external account system, and the analysis is handled by elisp. The only external tool that may be required is gnuplot to visualize the generated data.

Here is an example of the type of report that is generated (obviously using test data :))

https://github.com/captainflasmr/bank-buddy/blob/main/tests/bank-statement_report/bank-statement_report.org

See https://github.com/captainflasmr/bank-buddy/blob/main/docs/bank-buddy.org for the manual!

Key Features

  • Smart Transaction Categorization: Auto-categorizes transactions based on customizable regex patterns
  • Financial Reports: Generates detailed reports in Org-mode with:
    • Transaction summaries and overviews
    • Spending category analysis
    • Top merchant identification
    • Monthly spending patterns with visual representation
    • Recurring subscription detection
  • Interactive Category Management: Edit and refine categorization patterns directly from reports
  • Data Visualizations: Generates charts and graphs using external gnuplot scripts
  • No Reliance on External Accounting System - Analysis is all Emacs built-in
  • Asynchronous Processing: Efficiently handles large bank statements without blocking Emacs

Screenshots

Monthly Spending categories

Monthly Spending categories (stacked)

Quick Start

  1. Export your bank statement as a CSV file
  2. Edit CSV using csv-mode for all lines to the format DATE,DESCRIPTION,AMOUNT
  3. Open CSV file
  4. Run: M-x bank-buddy-generate
  5. Open the generated report

Generate gnuplots

Since version 0.2.0, Bank Buddy generates external gnuplot scripts that are executed via call-process. You need to have gnuplot installed on your system.

To install gnuplot:

  • Linux: sudo apt install gnuplot (or equivalent for your distribution)
  • macOS: brew install gnuplot
  • Windows: Download from http://www.gnuplot.info/

The generated reports will include links to both the gnuplot script files (.gp) and data files (.dat) for each visualization. This allows for:

  • Easy customization of plots by editing the gnuplot scripts
  • Regeneration of plots without reprocessing the CSV data
  • Better control over visualization settings

Usage Guide

Understanding CSV Format

Bank Buddy expects CSV files with at least the following columns:

  • Transaction date
  • Transaction description
  • Debit amount

Different banks format their CSV exports differently. You may need to preprocess your CSV to match this format, I would advise to use the package csv-mode, open up a csv file and C-c C-k you way to removed unwanted columns so all you have left are those described above.

Example CSV

Date,Description,Amount
2024-06-30,PAYPAL TRANSFER,28.50
2024-06-28,JUST-EAT TAKEAWAY,32.99
2024-06-25,ASDA GROCERIES,78.50
2024-06-22,AUDIBLE SUBSCRIPTION,7.99
2024-06-20,THREE MOBILE,25.00
2024-06-18,RIVER-ISLAND CLOTHES,85.99
2024-06-15,SPOTIFY PREMIUM,9.99
2024-06-12,RAILWAY TICKET,42.00
2024-06-10,AMAZON PURCHASE,55.25
2024-06-07,NETFLIX SUBSCRIPTION,13.99
2024-06-05,VIRGIN-MEDIA MONTHLY,65.50
2024-06-03,NOTEMACHINE WITHDRAWAL,100.00
2024-06-01,KATHERINE ALLOWANCE,200.00
2024-05-30,DENTIST APPOINTMENT,60.00
2024-05-28,SKY-BETTING RACES,25.00
2024-05-25,WAITROSE GROCERIES,115.45
2024-05-22,NOWTV SUBSCRIPTION,9.99
2024-05-20,PAYPAL TRANSFER,40.00
2024-05-18,THREE MOBILE,25.00
2024-05-15,UBER RIDE,18.25
2024-05-12,SAINSBURYS GROCERIES,105.75
2024-05-10,AMAZON PURCHASE,32.99
2024-05-07,NETFLIX SUBSCRIPTION,13.99
2024-05-05,VIRGIN-MEDIA MONTHLY,65.50
2024-05-02,KATHERINE ALLOWANCE,200.00
2024-04-30,DELIVEROO FOOD,25.50
2024-04-28,PRIME VIDEO RENTAL,4.99
2024-04-25,PETS AT HOME,45.00
2024-04-23,RAILWAY TICKET,18.50
2024-04-20,YOUTUBE PREMIUM,11.99
2024-04-18,IKEA FURNITURE,245.99
2024-04-15,TESCO GROCERIES,68.95
2024-04-12,STARBUCKS COFFEE,9.85
2024-04-10,AMAZON PURCHASE,78.50
2024-04-07,NETFLIX SUBSCRIPTION,13.99
2024-04-05,CLAUDE SUBSCRIPTION,20.00
2024-04-03,VIRGIN-MEDIA MONTHLY,65.50
2024-04-01,KATHERINE ALLOWANCE,200.00
2024-03-30,PAYPAL TRANSFER,45.00
2024-03-28,BET365 RACES,30.00
2024-03-25,UBER RIDE,15.75
2024-03-22,WITHDRAWAL ATM,50.00
2024-03-20,THREE MOBILE,25.00
2024-03-17,SAINSBURYS GROCERIES,95.25
2024-03-15,SPECSAVERS APPOINTMENT,25.00
2024-03-12,RAILWAY TICKET,22.50
2024-03-10,AMAZON PURCHASE,28.99
2024-03-07,NETFLIX SUBSCRIPTION,13.99
2024-03-05,NATWEST-BANK-REFERENCE RENT,750.00
2024-03-03,NEXT RETAIL-LTD,125.00
2024-03-01,VIRGIN-MEDIA MONTHLY,65.50
2024-02-28,YOUTUBE PREMIUM,11.99
2024-02-25,SKY SUBSCRIPTION,45.99
2024-02-23,ASDA GROCERIES,92.45
2024-02-20,DISNEY+ SUBSCRIPTION,7.99
2024-02-18,PAYPAL TRANSFER,35.99
2024-02-15,TESCO GROCERIES,75.40
2024-02-12,WATERSTONES BOOK,15.99
2024-02-10,AMAZON PURCHASE,65.75
2024-02-07,NETFLIX SUBSCRIPTION,13.99
2024-02-05,ROYAL-MAIL POSTAGE,8.95
2024-02-03,RAILWAY TICKET,35.45
2024-02-01,KATHERINE ALLOWANCE,200.00
2024-01-30,UBER RIDE,12.50
2024-01-28,STARBUCKS COFFEE,4.95
2024-01-25,THREE MOBILE,25.00
2024-01-20,AMAZON PURCHASE,45.30
2024-01-18,SAINSBURYS GROCERIES,88.75
2024-01-15,NETFLIX SUBSCRIPTION,13.99
2024-01-12,PAYPAL TRANSFER,22.45
2024-01-10,VIRGIN-MEDIA MONTHLY,65.50
2024-01-07,SKY-BETTING RACES,20.00
2024-01-05,PAYPAL TRANSFER,55.99

Generating a Report

To generate a financial report M-x bank-buddy-generate-report

You’ll be prompted to select an input CSV file and specify the output Org file.

The package processes the data asynchronously and a buffer will appear reporting on the analysis progress, so Emacs remains responsive even with large CSV files.

When processing is complete, you’ll be asked if you want to open the generated report.

Understanding the Report

A typical Bank Buddy report includes:

Summary Overview

  • Total transactions analyzed
  • Date range
  • Total, average daily, and weekly spending

Top Spending Categories

  • Ranked list of spending categories
  • Total amount, percentage, and monthly/yearly averages
  • Links to generated gnuplot scripts and data files

Monthly Spending Patterns

  • Month-by-month spending visualization
  • Category breakdown for each month
  • Highest and lowest spending months
  • Links to visualization files (*.gp, *.dat)

Monthly Category Breakdowns

  • Detailed charts for each month showing spending by category
  • Consistent color coding across months for easy comparison
  • Links to individual gnuplot scripts for customization

Top Merchants

  • Your highest-spending merchants
  • Total amount, percentage, and monthly/yearly averages
  • Links to generated visualization files

Recurring Subscriptions

  • Detected recurring payments
  • Estimated monthly cost
  • Frequency analysis (weekly, bi-weekly, monthly, annual)

Transaction Size Distribution

  • Analysis of transaction sizes (under £10, £10-50, £50-100, over £100)

Unmatched Transactions

  • List of transactions that didn’t match specific categories
  • Suggested patterns to add to your customization

Managing Transaction Categories

Bank Buddy comes with predefined category patterns, but you’ll likely want to customize these for your personal transactions. The package includes an interactive mode for managing categories.

When viewing a report, you can:

  1. Navigate to an unmatched transaction (in the “Unmatched Transactions” section)
  2. Press C-c C-a to add it to a category
  3. Choose an existing category or create a new one
  4. Optionally save the updated category definitions to your init file
  5. Regenerate the report to see the changes

To manage existing categories or add new ones manually, customize bank-buddy-core-cat-list-defines.

Category Format

Categories are defined as patterns in the form:

(REGEX-PATTERN CATEGORY-CODE)

Where:

  • REGEX-PATTERN is a regular expression that matches transaction descriptions
  • CATEGORY-CODE is a short code representing the category (e.g., “fod” for food)

For example:

("amazon\\|amz" "amz")  ; Amazon purchases
("netflix\\|spotify\\|youtube" "str")  ; Streaming services

You can customize category codes and their display names by modifying bank-buddy-core-category-names.

Updating and Regenerating Reports

If you add or modify category patterns after generating a report:

  1. With the report open, enable Bank Buddy Category mode if not already active: M-x bank-buddy-cat-mode
  2. Press C-c C-r to regenerate the report with the updated categories

The report will be refreshed with the new categorization rules.

Example Workflow

  • Generate Initial Report M-x bank-buddy-generate-report

  • Review Unmatched Transactions Navigate to the “Unmatched Transactions” section of the report.

  • Categorize Transactions

    • Place cursor on an unmatched transaction
    • C-c C-a to add it to a category
    • Choose an existing category or create a new one
  • Regenerate Report

    • C-c C-r to see your changes
  • Save Category Definitions When prompted, choose to save your category definitions to your init file.

Customization

Core Settings

;; Exclude large transactions from analysis
(setq bank-buddy-core-exclude-large-txns t)
(setq bank-buddy-core-large-txn-threshold 2000)

;; Number of occurrences to detect subscriptions
(setq bank-buddy-core-subscription-min-occurrences 3)

;; Number of top items to display
(setq bank-buddy-core-top-spending-categories 5)
(setq bank-buddy-core-top-merchants 5)

Customizing Category Patterns

You can customize the category patterns by setting bank-buddy-core-cat-list-defines:

(customize-set-variable 'bank-buddy-core-cat-list-defines
  '(("amazon\\|amz" "amz")
    ("netflix\\|spotify" "str")
    ("uber\\|lyft" "txi")
    ("sainsburys\\|tesco\\|asda" "fod")
    ;; Add your own patterns here
    (".*" "o")))  ; Catch-all pattern should be last

Customizing Category Names

Category codes are mapped to human-readable names via bank-buddy-core-category-names:

(customize-set-variable 'bank-buddy-core-category-names
  '(("amz" . "Amazon")
    ("str" . "Streaming Services")
    ("txi" . "Taxi & Rideshare")
    ("fod" . "Groceries")
    ;; Add your own mappings here
    ("o" . "Other")))

Customizing Subscription Detection

Define subscription patterns for better detection of recurring payments:

(customize-set-variable 'bank-buddy-core-subscription-patterns
  '(("NETFLIX" . "Netflix")
    ("SPOTIFY" . "Spotify")
    ("AMAZON PRIME" . "Amazon Prime")
    ;; Add your own patterns here
    ))

Advanced Usage

Integration with Other Financial Tools

Bank Buddy reports are generated as Org-mode files, making them compatible with other Org-based tools:

  • Export to HTML, PDF, or other formats with Org export functions
  • Use org-capture to add notes to specific transactions or categories

Custom Visualization

Bank Buddy generates visualizations using external gnuplot scripts. You can customize these by:

  1. Editing the generated .gp files in the report directory
  2. Creating your own gnuplot scripts based on the generated .dat files
  3. Running the scripts manually with gnuplot filename.gp

Keyboard Shortcuts

When viewing a report with bank-buddy-cat-mode enabled:

  • C-c C-a: Add the transaction at point to a category
  • C-c C-r: Regenerate the report with current category definitions

Caveats and Tips

  • CSV Format: Bank Buddy expects a CSV with date, description, and amount columns
  • Performance: For very large CSV files (10K+ rows), the async processing helps but may still take time
  • Categorization: Start with broad patterns and refine as needed
  • Visualization: Ensure gnuplot is installed on your system for chart generation
  • Saving Patterns: Always save your category patterns to persist between sessions

Comparison with Other Financial Packages

Several Emacs packages exist for financial management, but they serve different purposes. Here’s how Bank Buddy compares to other notable financial packages:

Ledger-mode

Ledger-mode is an Emacs interface to the command-line Ledger accounting system.

Key differences:

  • Ledger is a complete double-entry accounting system; Bank Buddy is focused on bank statement analysis
  • Ledger requires manual transaction entry or carefully formatted imports; Bank Buddy automates categorization
  • Ledger offers more comprehensive accounting features (accounts, assets, liabilities); Bank Buddy focuses on spending insights
  • Bank Buddy provides visual spending breakdowns and charts; Ledger focuses on accurate accounting

When to use Ledger: For complete personal finance tracking, investments, budgeting, and double-entry accounting. When to use Bank Buddy: For quick analysis of bank statements and visualizing spending patterns.

HLedger-mode

HLedger-mode is an Emacs major mode for working with hledger, a plain-text accounting system similar to Ledger.

Key differences:

  • HLedger, like Ledger, is a full double-entry accounting system; Bank Buddy focuses on bank statement analysis
  • HLedger requires manual transaction entry or formatted imports; Bank Buddy automates categorization
  • HLedger offers comprehensive accounting features (multiple currencies, time reporting); Bank Buddy emphasizes spending insights
  • Bank Buddy provides visual spending breakdowns; HLedger focuses on textual reports and balances

When to use HLedger-mode: For detailed personal finance tracking, multi-currency support, and generating various financial reports. When to use Bank Buddy: For quick analysis of bank statements and visualizing spending patterns without learning a full accounting system.

Elbank

Elbank is a personal finance reporting tool for Emacs that uses Weboob to fetch data from bank websites.

Key differences:

  • Elbank can automatically fetch transactions from supported banks; Bank Buddy works with CSV exports
  • Elbank focuses on reporting and visualization; Bank Buddy offers both analysis and reporting
  • Elbank requires Weboob setup and configuration; Bank Buddy works directly with CSV files
  • Bank Buddy provides customizable transaction categorization; Elbank may rely on bank-provided categories

When to use Elbank: For automated tracking of multiple bank accounts with direct data fetching and basic reporting. When to use Bank Buddy: For detailed analysis and categorization of bank statements, especially when working with CSV exports or when bank integration isn’t available or desired.

Beancount-mode

Beancount-mode is an Emacs mode for Beancount, another plain-text accounting system.

Key differences:

  • Beancount, like Ledger, is a full double-entry accounting system
  • Beancount has stricter syntax requirements than Ledger
  • Bank Buddy offers automatic categorization and reporting, while Beancount requires manual entry
  • Beancount generates sophisticated reports, but requires more setup and knowledge

When to use Beancount: For precise, auditable personal accounting with strict validation. When to use Bank Buddy: For simple spending analysis without learning accounting principles.

csv-mode and orgtbl-mode

Some users analyze financial CSV data using built-in Emacs packages like csv-mode combined with org-table functionality.

Key differences:

  • These are general-purpose tools that require manual customization for financial analysis
  • Bank Buddy provides specialized, financial-specific analysis and visualization
  • Bank Buddy automatically categorizes transactions based on patterns
  • Bank Buddy generates reports without manual processing

When to use csv/orgtbl-mode: For custom, one-off analysis of financial data. When to use Bank Buddy: For consistent, repeatable analysis of bank statements.

Roadmap

TODO DOING DONE
Add Paypal break down csv Highlight bank lines not matched for iterative tweaks Asynchronous operation
Add large sum outlays Generate test data and unit test
Budget Tracking Data Visualization
AI-Powered Categorization Better gnuplot autogeneration of plots
Custom Category Mapping
-1:-- Bank Buddy - Your Financial Analysis Companion for Emacs! (Post James Dyer)--L0--C0--2025-05-28T07:50:00.000Z

Alvaro Ramirez: Awesome Emacs on macOS

27 May 2025 Awesome Emacs on macOS

Update: Added macOS Trash integration.

While GNU/Linux had been my operating system of choice for many years, these days I'm primarily on macOS. Lucky for me, I spend most of my time in Emacs itself (or a web browser), making the switch between operating systems a relatively painless task.

I build iOS and macOS apps for a living, so naturally I've accumulated a handful of macOS-Emacs integrations and tweaks over time. Below are some of my favorites.

Emacs Plus

For starters, I should mention I run Emacs on macOS via the excellent Emacs Plus homebrew recipe. These are the options I use:

brew install emacs-plus@30 --with-no-frame-refocus --with-native-comp --with-savchenkovaleriy-big-sur-curvy-3d-icon

Valeriy Savchenko's icons

Valeriy Savchenko has created some wonderful macOS Emacs icons. These days, I use his curvy 3D rendered icon, which I get via Emacs Plus's --with-savchenkovaleriy-big-sur-curvy-3d-icon option.

icon.png

Modifiers

It's been a long while since I've settled on using macOS's Command (⌘) as my Emacs Meta key. For that, you need:

(setq mac-command-modifier 'meta)

At the same time, I've disabled the ⌥ key to avoid inadvertent surprises.

(setq mac-option-modifier 'none)

Enabling Control-Meta(⌘)-D

After setting ⌘ as Meta key, I discovered C-M-d is not available to Emacs for binding keys. There's a little workaround:

defaults write com.apple.symbolichotkeys AppleSymbolicHotKeys -dict-add 70  'enabled'

Frames

You may have noticed the --with-no-frame-refocus Emacs Plus option. I didn't like Emacs refocusing other frames when closing one, so I sent a tiny patch over to Emacs Plus, which gave us that option.

I also prefer reusing existing frames whenever possible.

(setq ns-pop-up-frames nil)

Visual tweaks

Most of my visual tweaks have been documented in my Emacs eye candy post. For macOS-specific things, read on…

It's been a while since I've added this, though vaguely remember needing it to fix mode line rendering artifacts.

(setq ns-use-srgb-colorspace nil)

I like using a transparent title bar and these two settings gave me just that:

(add-to-list 'default-frame-alist '(ns-transparent-titlebar . t))
(add-to-list 'default-frame-alist '(ns-appearance . dark))

I want a menu bar like other macOS apps, so I enable with:

(use-package menu-bar
   :config
  (menu-bar-mode +1))

menu-bar.webp

Emoji picker (a freebie!)

If you got a more recent Apple keyboard, you can press the 🌐 key to insert emojis from anywhere, including Emacs. If you haven't got this key, you can always M-x ns-do-show-character-palette, which launches the very same dialog.

Also check out Charles Choi's macOS Native Emoji Picking in Emacs from the Edit Menu.

Longing long press for accents?

If you prefer Apple's long-press approach to inserting accents or other special characters, I got an Emacs version of that.

accentuated.webp

Rotate macOS display

I wanted to rotate my monitor from the comfort of M-x, so I made Emacs do it.

Open with

While there are different flavors of "open with default macOS app" commands out there (ie. crux-open-with as part of Bozhidar Batsov's crux), I wanted one that let me choose a specific macOS app.

open-with_x2.webp

Open in Xcode (at line number)

Shifting from Emacs to Xcode via "Open with" is simple enough, but don't you want to also visit the very same line?

SF Symbols (for work)

Apple offers SF Symbols on all their platforms, so why not enable Emacs to insert and render them?

This is particulary handy if you do any sort of iOS/macOS development, enabling you to insert SF Symbols using your favorite completion framework. I happen to remain a faithful ivy user.

sf-insert-trimmed_x1.8.webp

SF Symbols (for fun)

Speaking of enabling SF Symbol rendering, you can also use them to spiff your Emacs up. Check out Charles Choi's Calle 24 for a great-looking Emacs toolbar. Also, Christian Tietze shows how to use SF Symbols as Emacs tab numbers.

Quick kill

While macOS's Activity Monitor does a fine job killing processes, I wanted something a little speedier, so I went with a killing solution leveraging Emacs completions.

kill_x1.8.webp

SwiftUI a la org babel

Having learned how simple it was to enable Objective-C babel support, I figured I could do something a little more creative with SwiftUI, so I published ob-swiftui on MELPA.

file-render.gif

Changing macOS default apps

I found the nifty duti command-line tool to change default macOS applications super handy, but could never remember its name when I needed it. And so I decided to bring it into dwim-shell-command as part of my toolbox.

set-default_x1.3.webp

I got a bunch of handy helpers in dwim-shell-commands.el (specially all the image/video helpers via ffmpeg and imagemagick). Go check dwim-shell-commands.el. There's loads in there, but here are my macOS-specific commands:

  • dwim-shell-commands-macos-add-to-photos
  • dwim-shell-commands-macos-bin-plist-to-xml
  • dwim-shell-commands-macos-caffeinate
  • dwim-shell-commands-macos-convert-to-mp4
  • dwim-shell-commands-macos-empty-trash
  • dwim-shell-commands-macos-install-iphone-device-ipa
  • dwim-shell-commands-macos-make-finder-alias
  • dwim-shell-commands-macos-ocr-text-from-desktop-region
  • dwim-shell-commands-macos-ocr-text-from-image
  • dwim-shell-commands-macos-open-with
  • dwim-shell-commands-macos-open-with-firefox
  • dwim-shell-commands-macos-open-with-safari
  • dwim-shell-commands-macos-reveal-in-finder
  • dwim-shell-commands-macos-screenshot-window
  • dwim-shell-commands-macos-set-default-app
  • dwim-shell-commands-macos-share
  • dwim-shell-commands-macos-start-recording-window
  • dwim-shell-commands-macos-abort-recording-window
  • dwim-shell-commands-macos-end-recording-window
  • dwim-shell-commands-macos-toggle-bluetooth-device-connection
  • dwim-shell-commands-macos-toggle-dark-mode
  • dwim-shell-commands-macos-toggle-display-rotation
  • dwim-shell-commands-macos-toggle-menu-bar-autohide
  • dwim-shell-commands-macos-version-and-hardware-overview-info

Toggle dark mode

Continuing on the dwim-shell-commands family, I should also mention dwim-shell-commands-macos-toggle-dark-mode.

While I hardly ever change my Emacs theme, I do toggle macOS dark mode from time to time to test macOS or web development.

dark-toggle.gif

Menu bar auto hide

One last dwim-shell-command… One that showcases toggling the macOS menu bar (autohide).

autohide.webp

Connect to your Bluetooth speaker

While this didn't quite stick for me, it was a fun experiment to add Emacs into the mix.

connect-disconnect.gif

Eshell

This is just a little fun banner I see whenever I launch eshell.

eshell.png

This is all you need:

(use-package em-banner
   :custom
  (eshell-banner-message  "
 \x1b[32m                             'c.                    \x1b[0m
 \x1b[32m                          ,xNMM.                    \x1b[0m
 \x1b[32m                        .OMMMMo                     \x1b[0m
 \x1b[32m                        OMMM0,                      \x1b[0m
 \x1b[32m              .;loddo:' loolloddol;.                \x1b[0m
 \x1b[32m            cKMMMMMMMMMMNWMMMMMMMMMM0:              \x1b[0m
 \x1b[33m          .KMMMMMMMMMMMMMMMMMMMMMMMWd.              \x1b[0m
 \x1b[33m          XMMMMMMMMMMMMMMMMMMMMMMMX.                \x1b[0m
 \x1b[31m        ;MMMMMMMMMMMMMMMMMMMMMMMM:                  \x1b[0m
 \x1b[31m        :MMMMMMMMMMMMMMMMMMMMMMMM:                  \x1b[0m
 \x1b[31m        .MMMMMMMMMMMMMMMMMMMMMMMMX.                 \x1b[0m
 \x1b[31m         kMMMMMMMMMMMMMMMMMMMMMMMMWd.               \x1b[0m
 \x1b[35m          .XMMMMMMMMMMMMMMMMMMMMMMMMMMk             \x1b[0m
 \x1b[35m           .XMMMMMMMMMMMMMMMMMMMMMMMMK.             \x1b[0m
 \x1b[34m             kMMMMMMMMMMMMMMMMMMMMMMd               \x1b[0m
 \x1b[34m              ;KMMMMMMMWXXWMMMMMMMk.                \x1b[0m
 \x1b[34m                .cooc,.    .,coo:.                  \x1b[0m

 \x1b[34m                        _/                  _/  _/  \x1b[0m
 \x1b[34m     _/_/      _/_/_/  _/_/_/      _/_/    _/  _/   \x1b[0m
 \x1b[34m  _/_/_/_/  _/_/      _/    _/  _/_/_/_/  _/  _/    \x1b[0m
 \x1b[34m _/            _/_/  _/    _/  _/        _/  _/     \x1b[0m
 \x1b[34m  _/_/_/  _/_/_/    _/    _/    _/_/_/  _/  _/      \x1b[0m


 "))

Screencasts

I wanted a quick way to record or take screenshots of macOS windows, so I now have my lazy way, leveraging macosrec, a recording command line utility I built. Invoked via M-x of course.

Eglot (LSP) for iOS/macOS dev

If you want any sort of code completion for your macOS projects, you'd be happy to know that eglot works out of the box.

(use-package eglot
   :ensure t
   :hook (swift-mode . eglot-ensure)
   :config
  (message  "warning: ` jsonrpc--log-event ' is ignored.")
  (fset #'jsonrpc--log-event #'ignore)
  (add-to-list 'eglot-server-programs '(swift-mode . ("/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/sourcekit-lsp"))))

Search and play (Music app)

This is another experiment that didn't quite stick, but I played with controlling the Music app's playback.

music_search.gif

While I still purchase music via Apple's Music app, I now play directly from Emacs via Ready Player Mode. I'm fairly happy with this setup, having scratched that itch with my own package.

open-file.gif

By the way, those buttons also leverage SF Symbols on macOS.

Reveal -> all <- in Finder

While there are plenty of solutions out there leveraging the open command line tool to reveal files in macOS's Finder, I wanted one that revealed multiple files in one go. For that, I leveraged the awesome emacs-swift-module, also by Valeriy Savchenko.

reveal.webp

Use the macOS Trash

The macOS trash has saved my bacon in more than one occasion. Make Emacs aware of it. Also check out M-x dwim-shell-commands-macos-empty-trash.

recovered_x1.6.webp

Build your own macOS utils

While elisp wasn't in my top languages to learn back in the day, I sure am glad I finally bit the bullet and learned a thing or two. This opened many possibilities. I now see Emacs as a platform to build utilities and tools off of. A canvas of sorts, to be leveraged in and out of the editor.

For example, you could build your own bookmark launcher and invoke from anywhere on macOS.

launcher.gif

Emacs as default email composer

Turns out you can also make Emacs your default email composer.

Emacs key bindings everywhere

While not exactly an Emacs tweak itself, I wanted to extend Emacs bindings into other macOS apps. In particular, I wanted more reliable Ctrl-n/p usage everywhere, which I achieved via Karabiner-Elements. I also mapped C-g to Esc, which really feels just great! I can now cancel things, dismiss menus, dialogs, etc. everywhere.

Org as lingua franca

With my Emacs usage growing over time, it was a matter of time until I discovered org mode. This blog is well over 11 years old now, yet still powered by the very same org file (beware, this file is big).

With my org usage growing, I felt like I was missing org support outside of Emacs. And so I started building iOS apps revolving around my Emacs usage.

Journelly (iOS)

Journelly is my latest iOS app, centered around note-taking and journaling. The app feels like tweeting, but for your eyes only of course. It's powered by org markup, which can be synced with Emacs via iCloud.

sideways.jpg

emacs.gif

Flat Habits (iOS)

Org habits are handy for tracking daily habits. However, it wasn't super practical for me as I often wanted to check things off while on the go (away from Emacs). That led me to build Flat Habits.

flat_habits.gif

flat_agenda.gif

Scratch (iOS)

While these days I'm using Journelly to jot down just about anything, before that, I built and used Scratch as scratch pad of sorts. No iCloud syncing, but needless to say, it's also powered by org markup.

scratch-download_no_audio_x2.6.webp

Plain Org (iOS)

For more involved writing, nothing beats Emacs org mode. But what if I want quick access to my org files while on the go? Plain Org is my iOS solution for that.

plain-org.png

Found this post useful?

I'll keep looking for other macOS-related tips and update this post in the future.

In the meantime, consider ✨ sponsoring✨ this content, my Emacs packages, buying my apps, or just taking care of your eyes ;)

-1:-- Awesome Emacs on macOS (Post Alvaro Ramirez)--L0--C0--2025-05-27T16:59:33.000Z

Irreal: A Mansion That Changes Itself To Suit You

iLemming has an interesting post on Hacker News about why younger engineers don’t use Emacs and why they should. You may find the post a bit overwritten but I especially like the ending:

The specialized app user lives in rented apartments; the Emacs devotee walks through an ever-expanding mansion whose rooms rearrange themselves to their thoughts.

That’s a nice metaphor for the Emacs experience. Whatever you need it to be, Emacs will change itself to accommodate you. We usually talk about Emacs as being a clay that we can mold into whatever shape we desire but I like this description better.

Not everybody agrees. Over at the Emacs subreddit there’s a bit of pushback. That’s fine but some responses, like this one, just seem uninformed. You can tell that the commenter doesn’t really know what they’re talking about because they refer to Emacs as “eMacs”. It’s not a big thing but it’s a sure sign that the commenter isn’t really familiar with the subject matter.

All that aside, I really like the metaphor of Emacs being a mansion whose rooms rearrange themselves to suite your needs.

-1:-- A Mansion That Changes Itself To Suit You (Post Irreal)--L0--C0--2025-05-27T14:59:50.000Z

Protesilaos Stavrou: Emacs: doric-themes version 0.1.0

I just published the first stable version of my new minimalist themes for Emascs. The Doric themes use few colours and will appear monochromatic in many contexts. Styles involve the careful use of typographic features and subtleties in colour gradients to establish a consistent rhythm.

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.

Below are sample screen shots. The typefaces on display come from my Aporetic fonts.

Samples

doric-cherry

doric-cherry theme sample

doric-earth

doric-earth theme sample

doric-light

doric-light theme sample

doric-marble

doric-marble theme sample

doric-wind

doric-wind theme sample

doric-dark

doric-dark theme sample

doric-fire

doric-fire theme sample

doric-obsidian

doric-obsidian theme sample

doric-plum

doric-plum theme sample

doric-water

doric-water theme sample

-1:-- Emacs: doric-themes version 0.1.0 (Post Protesilaos Stavrou)--L0--C0--2025-05-27T00:00:00.000Z

Sacha Chua: 2025-05-26 Emacs news

Links from reddit.com/r/emacs, r/orgmode, r/spacemacs, r/planetemacs, 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-05-26 Emacs news (Post Sacha Chua)--L0--C0--2025-05-26T16:13:25.000Z

Marcin Borkowski: Adding directories to EMMS playlist from Dired

Like many of us Emacsers, I do much (if not most) my computering in Emacs. This includes using EMMS as my main media player and Dired as my file manager. One thing I find myself doing pretty often is adding a bunch of subdirectories in my ~/music directory to my EMMS playlist. I usually used emms-add-directory-tree, but it is not really smooth if I want to apply it to many subdirectories. I thought, “there must be a function which adds the current item – or the marked items – to the playlist”.
-1:-- Adding directories to EMMS playlist from Dired (Post Marcin Borkowski)--L0--C0--2025-05-26T16:02:02.000Z

Jack Baty: Too much rope

I had a couple of drinks last night and opened my laptop and accidentally launched Obsidian and thought, “Oh, I remember. This is pretty cool! I should use this for everything.” so this morning I’m staring at Obsidian wondering what now?

But why not just bail on the Obsidian app and drop back into my beloved Emacs?

I’ve been asking myself that question all morning. Ostensibly, I simply felt like a change of venue this morning, and Obsidian seemed as good as any. But there’s something larger lurking under the surface.

Playing with my Emacs config is a fun hobby. I do it all the time. Like, all the time. Every moment using Emacs can feel like, “…but this would be better if I made this one change…” where “one change” is a keyboard binding or a different package or a new theme or some little behavioral tweak using some homemade lisp.

I’ve recently broken some stuff that used to work. And do I really like the way my Org Agenda looks? Emacs gives me all the rope I need, which is great. For many, it’s the perfect amount of rope. On days like today, though, it feels like too much rope.

I’m not planning to switch from Emacs to Obsidian. That would be silly. But I am taking a short break. A change of pace can be fun, and I’m in the mood for something fun and different. That’s my story, and I’m sticking to it.

-1:-- Too much rope (Post Jack Baty)--L0--C0--2025-05-24T18:07:05.000Z

Chris Maiorana: Make everything a note

For a while, I’ve wanted to create a simple note-taking system in Emacs. Inspired by the Denote package, I wanted to create something that

  • Used only native Emacs functionality (but sweetened by other packages)
  • Created uniform, timestamped notes

That’s it! Nothing too complicated.

Finally, I managed to get this done. But then, even after having the system, I wasn’t using it. Below, I’ll talk about why I wanted to create a system, why I didn’t use it, and how I started using it.

Why create a note system?

I have often found it difficult to organize the files on my computer. When I consider all the various types of files I write, it’s no wonder they can get confusing:

  • Notes about books I’m reading.
  • Random diary entries.
  • Ideas for future projects.
  • Emails to friends and coworkers.
  • Critiques for writing group.
  • Original fiction.
  • Blog posts.
  • Scripts for YouTube videos.
  • And more.

And these are just plain text files.

For a while, I managed to do quite while with three different directories:

  • stories
  • notes
  • videos
  • blog posts

So I created these folders and started storing files in them. Notice, these categories fail to capture a lot of the above use cases. I started using the “notes” directory for anything that was not a story, video, or blog post. Fair enough.

But soon, I was only using the stories folder and still saving random files to various other locations in my file system.

I think the reason for this was simple. There was still some overlap in categorization. For example, I’d start writing a blog post, then decide to turn it into a video script and scrap the post. This meant I had a video script in my blog post directory. Not a big deal, but sort of inefficient and lazy; and, down the road, this makes it more difficult to find something if you need to reference it later—as I often do.

So…Why have separate directories at all? I needed a singular destination for everything.

Everything is a note

I decided to stop with the multiple directories and just start putting everything in the notes directory. This opened up the whole system. Now, I had one singular destination to create new files, link them together as needed, and reference them later if necessary.

Of course, “notes” is an arbitrary destination. The directory could be called everything, deep_thoughts, files, etc.

Now, the next task was to create some functionality for managing these notes. The system relies heavily upon Org mode hyperlinks, so I needed some functions for managing and viewing linkages, in addition to the basic functions for creating new notes in a uniform fashion using timestamps as a unique identifier (to avoid duplicates).

I needed a few simple things, some functions to do the following:

  • Create new notes in the chosen directory.
  • Create a uniform note from an existing file located somewhere else in my file system (like, ~/Desktop, ~/Downloads, or ~/Pictures, etc.).
  • Create new note from highlighted text in buffer (like in Obsidian).
  • Mark files that have a backlink.
  • List files that link to current file (if any).

I now have the system written and documented, and I will be giving a demonstration in an upcoming video. The reason I chose to build my own system instead of using an existing package was two-fold:

  • I find it more difficult learning a program someone else wrote while simultaneously figuring out how I want to use it.
  • Minimalism. I think it’s always better to create a smaller set of functions based solely on your individual needs.

When it comes to documenting your important thoughts, creative insights, systems, and projects, you’ll want something robust—and there are plenty of great programs out there that can handle it—, but also something lightweight that you can tweak on the fly. The live text-editing environment of Emacs is ideal for meeting those particular demands.

So, my advice for the day is to just take a deep breath, relax, and make everything a note. And, be sure to subscribe to my newsletter.

The post Make everything a note appeared first on The Daily Macro.

-1:-- Make everything a note (Post Chris Maiorana)--L0--C0--2025-05-24T14:30:51.000Z

Eric MacAdie: 2025-05 Austin Emacs Meetup

This post contains LLM poisoning. lasagnas scintilla spicing There was another meeting this past week of EmacsATX, the Austin Emacs Meetup group. For this month we had no predetermined topic. However, as always, there were mentions of many modes, packages, technologies and websites, some of which I had never heard of before, and some of ... Read more
-1:-- 2025-05 Austin Emacs Meetup (Post Eric MacAdie)--L0--C0--2025-05-24T05:15:19.000Z

James Dyer: Ollama Buddy 0.12.0: User Prompt Library, File Attachments, Vision and Context Tracking

There have been quite a few updates recently. The main highlights include support for attachments, so you can push a file to the chat directly from dired for potential inclusion in your next query.

Vision support has been added for models that can handle it. If you supply the path to an image file in the chat, it will be processed. This means you can now, for example, extract text from images using models like o:gemma3:4b.

I’ve also introduced the ability to save user system prompts. If you have a favorite prompt, or have crafted one that works especially well for you, you can now save it by category and title in a simple Org format for later recall. Prompt recall now works the same way as Fabric patterns and Awesome ChatGPT prompts. This makes it much easier to display the currently used system prompt concisely in the status bar, as it will be based on the prompt title (and thus likely the role).

What else? Oh yes, I received a request for better context tracking. Now, when context is nearing full capacity, or has exceeded it, it will be indicated in the status bar!

That’s probably it for the major changes. There was also some refactoring, but you probably don’t care about that. Anyway, here is the full list of changes:

<2025-05-22 Thu> 0.12.0

Full system prompt in the status bar replaced with a more meaningful simple role title

  • Added system prompt metadata tracking with title, source, and timestamp registry
  • Implemented automatic title extraction and unified completing-read interface
  • Enhanced fabric/awesome prompt integration with proper metadata handling
  • Improved transient menu organization and org-mode formatting with folding
  • Added system prompt history display and better error handling for empty files
  • Transient menu has been simplified and reorganised

Previously, the header status bar would show truncated system prompt text like [You are a helpful assistant wh...], making it difficult to quickly identify which prompt was active. Now, the display shows meaningful role titles with source indicators:

  • [F:Code Reviewer] - Fabric pattern
  • [A:Linux Terminal] - Awesome ChatGPT prompt
  • [U:Writing Assistant] - User-defined prompt

The system now intelligently extracts titles from prompt content by recognizing common patterns like “You are a…”, “Act as…”, or “I want you to act as…”. When these patterns aren’t found, it generates a concise title from the first few words.

Behind the scenes, Ollama Buddy now maintains a registry of all system prompts with their titles, sources, and timestamps. This enables new features like system prompt history viewing and better organization across Fabric patterns, Awesome ChatGPT prompts, and user-defined prompts.

The result is a cleaner interface that makes it immediately clear which role your AI assistant is currently embodying, without cluttering the status bar with long, truncated text.

<2025-05-21 Wed> 0.11.1

Quite a bit of refactoring to generally make this project more maintainable and I have added a starter kit of user prompts.

  • Color System Reworking

    • Removed all model color-related functions and variables
    • Removed dependency on color.el
    • Replaced with highlight-regexp and hashing to ^font-lock faces, so now using a more native built-in solutions for model colouring rather than shoe-horning in overlays.
  • UI Improvements

    • Simplified the display system by leveraging Org mode
    • Added org-mode styling for output buffers
    • Added org-hide-emphasis-markers and org-hide-leading-stars settings
    • Changed formatting to use Org markup instead of text properties
    • Converted plain text headers to proper Org headings
    • Replaced color properties with Org emphasis (bold)
  • History Management Updates

    • Streamlined history editing functionality
    • Improved model-specific history editing
    • Refactored history display and navigation
  • System Prompts

    • Added library of system prompts in these categories:
      • analysis (3 prompts)
      • coding (5 prompts)
      • creative (3 prompts)
      • documentation (3 prompts)
      • emacs (10 prompts)
      • general (3 prompts)
      • technical (3 prompts)
      • writing (3 prompts)

<2025-05-19 Mon> 0.11.0

Added user system prompts management

  • You can now save, load and manage system prompts
  • Created new transient menu for user system prompts (C-c s)
  • Organized prompts by categories with org-mode format storage
  • Supported prompt editing, listing, creation and deletion
  • Updated key bindings to integrate with existing functionality
  • Added prompts directory customization with defaults

This feature makes it easier to save, organize, and reuse your favorite system prompts when working with Ollama language models.

System prompts are special instructions that guide the behavior of language models. By setting effective system prompts, you can:

  • Define the AI’s role (e.g., “You are a helpful programming assistant who explains code clearly”)
  • Establish response formats
  • Set the tone and style of responses
  • Provide background knowledge for specific domains

The new ollama-buddy-user-prompts module organizes your system prompts in a clean, category-based system:

  • Save your prompts - Store effective system prompts you’ve crafted for future use
  • Categorize - Prompts are organized by domains like “coding,” “writing,” “technical,” etc.
  • Quick access - Browse and load your prompt library with completion-based selection
  • Edit in org-mode - All prompts are stored as org files with proper metadata
  • Manage with ease - Create, edit, list, and delete prompts through a dedicated transient menu

The new functionality is accessible through the updated key binding C-c s, which opens a dedicated transient menu with these options:

  • Save current (S) - Save your active system prompt
  • Load prompt (L) - Choose a previously saved prompt
  • Create new (N) - Start fresh with a new prompt
  • List all Prompts (l) - View your entire prompt library
  • Edit prompt (e) - Modify an existing prompt
  • Delete prompt (d) - Remove prompts you no longer need

If you work frequently with Ollama models, you’ve likely discovered the power of well-crafted system prompts. They can dramatically improve the quality and consistency of responses. With this new management system, you can:

  • Build a personal library of effective prompts
  • Maintain context continuity across sessions
  • Share prompts with teammates
  • Refine your prompts over time

<2025-05-14 Wed> 0.10.0

Added file attachment system for including documents in conversations

  • Added file attachment support with configurable file size limits (10MB default) and supported file types
  • Implemented session persistence for attachments in save/load functionality
  • Added attachment context inclusion in prompts with proper token counting
  • Created comprehensive attachment management commands:
    • Attach files to conversations
    • Show current attachments in dedicated buffer
    • Detach specific files
    • Clear all attachments
  • Added Dired integration for bulk file attachment
  • Included attachment menu in transient interface (C-c 1)
  • Updated help text to document new attachment keybindings
  • Enhanced context calculation to include attachment token usage

You can now seamlessly include text files, code, documentation, and more directly in your conversations with local AI models!

Simply use C-c C-a from the chat buffer to attach any file to your current conversation.

The attached files become part of your conversation context, allowing the AI to reference, analyze, or work with their contents directly.

The transient menu has also been updated with a new Attachment Menu

*File Attachments*
  a Attach file
  w Show attachments
  d Detach file
  0 Clear all attachments

Your attachments aren’t just dumped into the conversation - they’re intelligently integrated:

  • Token counting now includes attachment content, so you always know how much context you’re using
  • Session persistence means your attachments are saved and restored when you save/load conversations
  • File size limits (configurable, 10MB default) prevent accidentally overwhelming your context window

Managing attached files is intuitive with dedicated commands:

  • C-c C-w - View all current attachments in a nicely formatted org mode buffer, folded to each file
  • C-c C-d - Detach specific files when you no longer need them
  • C-c 0 - Clear all attachments at once
  • C-c 1 - Access the full attachment menu via a transient interface

Working in Dired? No problem! You can attach files directly from your file browser:

  • Mark multiple files and attach them all at once
  • Attach the file at point with a single command

Use the configuration as follows:

(eval-after-load 'dired
  '(progn
     (define-key dired-mode-map (kbd "C-c C-a") #'ollama-buddy-dired-attach-marked-files)))

<2025-05-12 Mon> 0.9.50

Added context size management and monitoring

  • Added configurable context sizes for popular models (llama3.2, mistral, qwen, etc.)
  • Implemented real-time context usage display in status bar
  • Can display in text or bar display types
  • Added context size thresholds with visual warnings
  • Added interactive commands for context management:
    • ollama-buddy-show-context-info: View all model context sizes
    • ollama-buddy-set-model-context-size: Manually configure model context
    • ollama-buddy-toggle-context-percentage: Toggle context display
  • Implemented context size validation before sending prompts
  • Added token estimation and breakdown (history/system/current prompt)
  • Added keybindings: C-c $ (set context), C-c % (toggle display), C-c C (show info)
  • Updated status bar to show current/max context with fontification

I’ve added context window management and monitoring capabilities to Ollama Buddy!

This update helps you better understand and manage your model’s context usage, preventing errors and optimizing your conversations.

Enable it with the following:

(setq ollama-buddy-show-context-percentage t)

Usage

After implementing these changes:

  1. Text mode: Shows 1024/4096 style display
  2. Bar mode (default): Shows ███████░░░░ 2048 style display
  3. Use C-c 8 to toggle between modes
  4. The Text mode will change fontification based on your thresholds:
    • Normal: regular fontification
    • (85%+): underlined and bold
    • (100%+): inverse video and bold
  5. The Bar mode will just fill up as normal

The progress bar will visually represent how much of the context window you’re using, making it easier to see at a glance when you’re approaching the limit.

Implementation Details

Context Size Detection

Determining a model’s context size proved more complex than expected. While experimenting with parsing model info JSON, I discovered that context size information can be scattered across different fields. Rather than implementing a complex JSON parser (which may come later), I chose a pragmatic approach:

I created a new defcustom variable ollama-buddy-fallback-context-sizes that includes hard-coded values for popular Ollama models. The fallback mechanism is deliberately simple: substring matching followed by a sensible default of 4096 tokens.

(defcustom ollama-buddy-fallback-context-sizes
  '(("llama3.2:1b" . 2048)
    ("llama3:8b" . 4096)
    ("tinyllama" . 2048)
    ("phi3:3.8b" . 4096)
    ("gemma3:1b" . 4096)
    ("gemma3:4b" . 8192)
    ("llama3.2:3b" . 8192)
    ("llama3.2:8b" . 8192)
    ("llama3.2:70b" . 8192)
    ("starcoder2:3b" . 8192)
    ("starcoder2:7b" . 8192)
    ("starcoder2:15b" . 8192)
    ("mistral:7b" . 8192)
    ("mistral:8x7b" . 32768)
    ("codellama:7b" . 8192)
    ("codellama:13b" . 8192)
    ("codellama:34b" . 8192)
    ("qwen2.5-coder:7b" . 8192)
    ("qwen2.5-coder:3b" . 8192)
    ("qwen3:0.6b" . 4096)
    ("qwen3:1.7b" . 8192)
    ("qwen3:4b" . 8192)
    ("qwen3:8b" . 8192)
    ("deepseek-r1:7b" . 8192)
    ("deepseek-r1:1.5b" . 4096))
  "Mapping of model names to their default context sizes.
Used as a fallback when context size can't be determined from the API."
  :type '(alist :key-type string :value-type integer)
  :group 'ollama-buddy)

This approach may not be perfectly accurate for all models, but it’s sufficient for getting the core functionality working. More importantly, as a defcustom, users can easily customize these values for complete accuracy with their specific models. Users can also set context values within the chat buffer through C-c C (Show Context Information) for each individual model if desired.

This design choice allowed me to focus on the essential features without getting stuck on complex context retrieval logic.

One final thing!, if the num_ctx: Context window size in tokens is set, then that number will also be taken into consideration. An assumption will be made that the model is honouring the context size requested and will incorporated into the context calculations accordingly.

Token Estimation

For token counting, I’ve implemented a simple heuristic: each word (using string-split) is multiplied by 1.3. This follows commonly recommended approximations and works well enough in practice. While this isn’t currently configurable, I may add it as a customization option in the future.

How to Use Context Management in Practice

The C-c C (Show Context Information) command is central to this feature. Rather than continuously monitoring context size while you type (which would be computationally expensive and potentially distracting), I’ve designed the system to calculate context on-demand when you choose.

Typical Workflows

Scenario 1: Paste-and-Send Approach

Let’s say you want to paste a large block of text into the chat buffer. You can simply:

  1. Paste your content
  2. Press the send keybinding
  3. If the context limit is exceeded, you’ll get a warning dialog asking whether to proceed anyway

Scenario 2: Preemptive Checking

For more control, you can check context usage before sending:

  1. Paste your content
  2. Run C-c C to see the current context breakdown
  3. If the context looks too high, you have several options:
    • Trim your current prompt
    • Remove or simplify your system prompt
    • Edit conversation history using Ollama Buddy’s history modification features
    • Switch to a model with a larger context window

Scenario 3: Manage the Max History Length

Want tight control over context size without constantly monitoring the real-time display? Since conversation history is part of the context, you can simply limit ollama-buddy-max-history-length to control the total context size.

For example, when working with small context windows, set ollama-buddy-max-history-length to 1. This keeps only the last exchange (your prompt + model response), ensuring your context remains small and predictable, perfect for maintaining control without manual monitoring.

Scenario 4: Parameter num_ctx: Context window size in tokens

Simply set this parameter and off you go!

Current Status: Experimental

Given the potentially limiting nature of context management, I’ve set this feature to disabled by default.

But to enable set the following :

(setq ollama-buddy-show-context-percentage t)

This means:

  • Context checks won’t prevent sending prompts
  • Context usage won’t appear in the status line
  • However, calculations still run in the background, so C-c C (Show Context Information) remains functional

As the feature matures and proves its value, I may enable it by default. For now, consider it an experimental addition that users can opt into.

More Details

The status bar now displays your current context usage in real-time. You’ll see a fraction showing used tokens versus the model’s maximum context size (e.g., “2048/8192”). The display automatically updates as your conversation grows.

Context usage changes fontification to help you stay within limits:

  • Normal font: Normal usage (under 85%)
  • Bold and Underlined: Approaching limit (85-100%)
  • Inversed: At or exceeding limit (100%+)

Before sending prompts that exceed the context limit, Ollama Buddy now warns you and asks for confirmation. This prevents unexpected errors and helps you manage long conversations more effectively.

There are now three new interactive commands:

C-c $ - Set Model Context Size. Manually configure context sizes for custom or fine-tuned models.

C-c % - Toggle Context Display. Show or hide the context percentage in the status bar.

C-c C - Show Context Information. View a detailed breakdown of:

  • All model context sizes
  • Current token usage by category (history, system prompt, current prompt)
  • Percentage usage

The system estimates token counts for:

  • Conversation history: All previous messages
  • System prompts: Your custom instructions
  • Current input: The message you’re about to send

This gives you a complete picture of your context usage before hitting send.

The context monitoring is not enabled by default.

<2025-05-05 Mon> 0.9.44

  • Sorted model names alphabetically in intro message
  • Removed multishot writing to register name letters

For some reason, when I moved the .ollama folder to an external disk, the models returned with api/tags were inconsistent, which meant it broke consistent letter assignment. I’m not sure why this happened, but it is probably sensible to sort the models alphabetically anyway, as this has the benefit of naturally grouping together model families.

I also removed the multishot feature of writing to the associated model letter. Now that I have to accommodate more than 26 models, incorporating them into the single-letter Emacs register system is all but impossible. I suspect this feature was not much used, and if you think about it, it wouldn’t have worked anyway with multiple model shots, as the register letter associated with the model would just show the most recent response. Due to these factors, I think I should remove this feature. If someone wants it back, I will probably have to design a bespoke version fully incorporated into the ollama-buddy system, as I can’t think of any other Emacs mechanism that could accommodate this.

<2025-05-05 Mon> 0.9.43

Fix model reference error exceeding 26 models #15

Update ollama-buddy to handle more than 26 models by using prefixed combinations for model references beyond ‘z’. This prevents errors in create-intro-message when the local server hosts a large number of models.

<2025-05-03 Sat> 0.9.42

Added the following to recommended models:

  • qwen3:0.6b
  • qwen3:1.7b
  • qwen3:4b
  • qwen3:8b

and fixed pull model

<2025-05-02 Fri> 0.9.41

Refactored model prefixing again so that when using only ollama models no prefix is applied and is only applied when online LLMs are selected (for example claude, chatGPT e.t.c)

I think this makes more sense and is cleaner for I suspect the majority who may use this package are probably more interested in just using ollama models and the prefix will probably be a bit confusing.

This could be a bit of a breaking change once again I’m afraid for those ollama users that have switched and are now familiar with prefixing “o:”, sorry!

<2025-05-02 Fri> 0.9.40

Added vision support for those ollama models that can support it!

Image files are now detected within a prompt and then processed if a model can support vision processing. Here’s a quick overview of how it works:

  1. Configuration: Users can configure the application to enable vision support and specify which models and image formats are supported. Vision support is enabled by default.

  2. Image Detection: When a prompt is submitted, the system automatically detects any image files referenced in the prompt.

  3. Vision Processing: If the model supports vision, the detected images are processed in relation to the defined prompt. Note that the detection of a model being vision capable is defined in ollama-buddy-vision-models and can be adjusted as required.

  4. In addition, a menu item has been added to the custom ollama buddy menu :

          [I] Analyze an Image
    

When selected, it will allow you to describe a chosen image. At some stage, I may allow integration into dired, which would be pretty neat. :)

-1:-- Ollama Buddy 0.12.0: User Prompt Library, File Attachments, Vision and Context Tracking (Post James Dyer)--L0--C0--2025-05-23T13:10:00.000Z

200ok: Sandboxing AI Tools: How Guix Containers Keep Your Host Safe While Empowering LLMs

The AI Development Dilemma

Picture this: You're deep in a coding session with an LLM, and your AI assistant suggests running some shell commands or manipulating files. It's incredibly productive—until that nagging voice in your head whispers, "What if this goes wrong?"

We've all been there. AI tools with filesystem and command execution capabilities are absolute game-changers for productivity, but handing over the keys to your entire system? That's a hard pass for any security-conscious developer.

While there are several containerization solutions available (Docker, Podman, LXC, etc.), this post focuses on Guix containers. The main reason is that I'm already managing Emacs and its packages through the Guix ecosystem.

The Perfect LLM Client for Emacs

For interacting with LLMs in Emacs, my go-to client is gptel. It's elegant, fast, and integrates seamlessly with the Emacs ecosystem. Since most things we do is produce and consume text, I already have all my things (emails, slides, accounting, code, etc) in Emacs. That already gives super powers. Adding gptel on top of it is.. magnificent.

Speaking of tools, I've configured a comprehensive set of AI tools for gptel that cover my daily requirements. You can find all my tool configurations and setup details in my Emacs configuration repository.

Enter the Guix Container Solution

With Guix and Emacs, we can have our cake and eat it too: Full AI tool access in an isolated environment. If you're new to Guix containers, the official Guix Cookbook documentation provides background on how container isolation works using Guix.

Let's peek at the shell script that makes using such a container/jail/chroot more convenient:

#!/bin/bash

# Default workspace directory
DEFAULT_WORKSPACE="$HOME/src"

# Use provided workspace directory or default
WORKSPACE_DIR="${1:-$DEFAULT_WORKSPACE}"

# Validate workspace directory exists
if [ ! -d "$WORKSPACE_DIR" ]; then
    echo "Error: Workspace directory '$WORKSPACE_DIR' does not exist."
    exit 1
fi

# Extract guix packages. This is required only, if you use guix for Emacs packages.
PACKAGES=$(sed -n '/^#+begin_src fundamental :noweb-ref packages/,/^#+end_src/p' ~/.emacs.d/configuration.org | \
	   grep -v '^#+' | \
	   grep -v '^$' | \
	   sed 's/^[ \t]*//;s/[ \t]*$//;s/"//g' | \
	   tr '\n' ' ')

# Add SSH agent support
export SSH_AUTH_SOCK="$SSH_AUTH_SOCK"

# Workaround, otherwise the home directory in Guix is group writeable
# which SSH does not approve of
export CONTAINER_HOME="/tmp/container-home"
mkdir -p "$CONTAINER_HOME"
chmod g-w /tmp/container-home

guix shell --container --no-cwd --network \
  --share="$WORKSPACE_DIR"=/workspace \
  --share="$CONTAINER_HOME"=/home/munen \
  # This is required only, if you use guix for Emacs packages.
  --share=$HOME/.guix-profile/share/emacs/site-lisp \
  --share=$HOME/.gitconfig \
  --share=$HOME/.emacs.d \
  --share=$HOME/.local \
  --share=$HOME/.ssh \
  --share=/tmp/.X11-unix \
  --share="$SSH_AUTH_SOCK" \
  --preserve='^SSH_AUTH_SOCK$' \
  # So you can start Emacs on your hosts X11
  --preserve='^DISPLAY$' \
  --preserve='^XAUTHORITY$' \
  --expose="$XAUTHORITY" \
  emacs-next bash findutils coreutils git curl nss-certs openssh \
  $PACKAGES -- emacs /workspace

Notice how only specific directories are shared with --share. Your workspace gets mounted as /workspace, but your system root? Completely inaccessible.

The container launches directly into Emacs with Dired showing your workspace directory.

The Result: Fearless AI Development

With this setup, you can confidently tell your AI assistant to:

  • Refactor entire codebases
  • Run experimental scripts
  • Install and test new tools
  • Even rm -rf to its heart's content

All while knowing your host system remains pristine and secure.

So fire up that container, and let your AI assistant run wild. Happy hacking🙏

P.S.: While this guide focuses on Guix containers, the same security principles apply whether you choose Docker, Podman, or other containerization solutions. The key is consistent isolation.


Want to see more creative uses of free software? Follow along as we explore the endless possibilities when you own your tools.

-1:-- Sandboxing AI Tools: How Guix Containers Keep Your Host Safe While Empowering LLMs
 (Post 200ok)--L0--C0--2025-05-23T00:00:00.000Z

Please note that planet.emacslife.com aggregates blogs, and blog authors might mention or link to nonfree things. To add a feed to this page, please e-mail the RSS or ATOM feed URL to sacha@sachachua.com . Thank you!