Sacha Chua: Playing around with org-db-v3 and consult: vector search of my blog post Org files, with previews

I tend to use different words even when I'm writing about the same ideas. When I use traditional search tools like grep, it can be hard to look up old blog posts or sketches if I can't think of the exact words I used. When I write a blog post, I want to automatically remind myself of possibly relevant notes without requiring words to exactly match what I'm looking for.

Demo

Here's a super quick demo of what I've been hacking together so far, doing vector search on some of my blog posts using the .org files I indexed with org-db-v3:

Screencast of my-blog-similar-link

Play by play:

  • 0:00:00 Use M-x my-blog-similar-link to look for "forgetting things", flip through results, and use RET to select one.
  • 0:00:25 Select "convert the text into a link" and use M-x my-blog-similar-link to change it into a link.
  • 0:00:44 I can call it with C-u M-x my-blog-similar-link and it will do the vector search using all of the post's text. This is pretty long, so I don't show it in the prompt.
  • 0:00:56 I can use Embark to select and insert multiple links. C-SPC selects them from the completion buffer, and C-. A acts on all of them.
  • 0:01:17 I can also use Embark's C-. S (embark-collect) to keep a snapshot that I can act on, and I can use RET in that buffer to insert the links.

Background

A few weeks ago, John Kitchin demonstrated a vector search server in his video Emacs RAG with LibSQL - Enabling semantic search of org-mode headings with Claude Code - YouTube. I checked out jkitchin/emacs-rag-libsql and got the server running. My system's a little slow (no GPU), so (setq emacs-rag-http-timeout nil) was helpful. It feels like a lighter-weight version of Khoj (which also supports Org Mode files) and maybe more focused on Org than jwiegley/rag-client. At the moment, I'm more interested in embeddings and vector/hybrid search than generating summaries or using a conversational interface, so something simple is fine. I just want a list of possibly-related items that I can re-read myself.

Of course, while these notes were languishing in my draft file, John Kitchin had already moved on to something else. He posted Fulltext, semantic text and image search in Emacs - YouTube, linking to a new vibe-coded project called org-db-v3 that promises to offer semantic, full-text, image, and headline search. The interface is ever so slightly different: POST instead of GET, a different data structure for results. Fortunately, it was easy enough to adapt my code. I just needed a small adapter function to make the output of org-db-v3 look like the output from emacs-rag-search.

(use-package org-db-v3
  :load-path "~/vendor/org-db-v3/elisp"
  :init
  (setq org-db-v3-auto-enable nil))

(defun my-org-db-v3-to-emacs-rag-search (query &optional limit filename-pattern)
  "Search org-db-v3 and transform the data to look like emacs-rag-search's output."
  (org-db-v3-ensure-server)
  (setq limit (or limit 100))
  (mapcar (lambda (o)
            `((source_path . ,(assoc-default 'filename o))
              (line_number . ,(assoc-default 'begin_line o))))
          (assoc-default 'results
                         (plz 'post (concat (org-db-v3-server-url) "/api/search/semantic")
                           :headers '(("Content-Type" . "application/json"))
                           :body (json-encode `((query . ,query)
                                                (limit . ,limit)
                                                (filename_pattern . ,filename-pattern)))
                           :as #'json-read))))

I'm assuming that org-db-v3 is what John's going to focus on instead of emacs-rag-search (for now, at least). I'll focus on that for the rest of this post, although I'll include some of the emacs-rag-search stuff just in case.

Indexing my Org files

Both emacs-rag and org-db-v3 index Org files by submitting them to a local web server. Here are the key files I want to index:

  • organizer.org: my personal projects and reference notes
  • reading.org: snippets from books and webpages
  • resources.org: bookmarks and frequently-linked sites
  • posts.org: draft posts
(dolist (file '("~/sync/orgzly/organizer.org"
                "~/sync/orgzly/posts.org"
                "~/sync/orgzly/reading.org"
                "~/sync/orgzly/resources.org"))
  (org-db-v3-index-file-async file))

(emacs-rag uses emacs-rag-index-file instead.)

Indexing blog posts via exported Org files

Then I figured I'd index my recent blog posts, except for the ones that are mostly lists of links, like Emacs News or my weekly/monthly/yearly reviews. I write my posts in Org Mode before exporting them with ox-11ty and converting them with the 11ty static site generator. I'd previously written some code to automatically export a copy of my Org draft in case people wanted to look at the source of a blog post, or in case I wanted to tweak the post in the future. (Handy for things like Org Babel.) This was generally exported as an index.org file in the post's directory. I can think of a few uses for a list of these files, so I'll make a function for it.

(defun my-blog-org-files-except-reviews (after-date)
  "Return a list of recent .org files except for Emacs News and weekly/monthly/yearly reviews.
AFTER-DATE is in the form yyyy, yyyy-mm, or yyyy-mm-dd."
  (setq after-date (or after-date "2020"))
  (let ((after-month (substring after-date 0 7))
        (posts (my-blog-posts)))
    (seq-keep
     (lambda (filename)
       (when (not (string-match "[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]-emacs-news" filename))
         (when (string-match "/blog/\\([0-9]+\\)/\\([0-9]+\\)/" filename)
           (let ((month (match-string 2 filename))
                 (year (match-string 1 filename)))
             (unless (string> after-month
                              (concat year "-" month))
               (let ((info (my-blog-post-info-for-url (replace-regexp-in-string "~/proj/static-blog\\|index\\.org$\\|\\.org$" "" filename) posts)))
                 (let-alist info

                   (when (and
                          info
                          (string> .date after-date)
                          (not (seq-intersection .categories
                                                 '("emacs-news" "weekly" "monthly" "yearly")
                                                 'string=)))
                     filename))))))))
     (sort
      (directory-files-recursively "~/proj/static-blog/blog" "\\.org$")
      :lessp #'string<
      :reverse t))))

This is in the Listing exported Org posts section of my config. I have a my-blog-post-info-for-url function that helps me look up the categories. I get the data out of the JSON that has all of my blog posts in it.

Then it's easy to index those files:

(mapc #'org-db-v3-index-file-async (my-blog-org-files-except-reviews))

Searching my blog posts

Now that my files are indexed, I want to be able to turn up things that might be related to whatever I'm currently writing about. This might help me build up thoughts better, especially if a long time has passed in between posts.

org-db-v3-semantic-search-ivy didn't quite work for me out of the box, but I'd written an Consult-based interface for emacs-rag-search-vector that was easy to adapt. This is how I put it together.

First I started by looking at emacs-rag-search-vector. That shows the full chunks, which feels a little unwieldy.

2025-10-09_10-05-58.png
Figure 1: Screenshot showing the chunks returned by a search for "semantic search"

Instead, I wanted to see the years and titles of the blog posts as a quick summary, with the ability to page through them for a quick preview. consult.el lets me define a custom completion command with that behavior. Here's the code:

(defun my-blog-similar-link (link)
  "Vector-search blog posts using `emacs-rag-search' and insert a link.
If called with \\[universal-argument\], use the current post's text.
If a region is selected, use that as the default QUERY.
HIDE-INITIAL means hide the initial query, which is handy if the query is very long."
  (interactive (list
                (if embark--command
                    (read-string "Link: ")
                  (my-blog-similar
                   (cond
                    (current-prefix-arg (my-11ty-post-text))
                    ((region-active-p)
                     (buffer-substring (region-beginning)
                                       (region-end))))
                   current-prefix-arg))))
  (my-embark-blog-insert-link link))

(defun my-embark-blog--inject-target-url (&rest args)
  "Replace the completion text with the URL."
  (delete-minibuffer-contents)
  (insert (my-blog-url (get-text-property 0 'consult--candidate (plist-get args :target)))))

(with-eval-after-load 'embark
  (add-to-list 'embark-target-injection-hooks '(my-blog-similar-link my-embark-blog--inject-target-url)))

(defun my-blog-similar (&optional query hide-initial)
  "Vector-search blog posts using `emacs-rag-search' and present results via Consult.
If called with \\[universal-argument\], use the current post's text.
If a region is selected, use that as the default QUERY.
HIDE-INITIAL means hide the initial query, which is handy if the query is very long."
  (interactive (list (cond
                      (current-prefix-arg (my-11ty-post-text))
                      ((region-active-p)
                       (buffer-substring (region-beginning)
                                         (region-end))))
                     current-prefix-arg))
  (consult--read
   (if hide-initial
       (my-org-db-v3-blog-post--collection query)
     (consult--dynamic-collection
         #'my-org-db-v3-blog-post--collection
       :min-input 3 :debounce 1))
   :lookup #'consult--lookup-cdr
   :prompt "Search blog posts (approx): "
   :category 'my-blog
   :sort nil
   :require-match t
   :state (my-blog-post--state)
   :initial (unless hide-initial query)))

(defvar my-blog-semantic-search-source 'org-db-v3)
(defun my-org-db-v3-blog-post--collection (input)
  "Perform the RAG search and format the results for Consult.
Returns a list of cons cells (DISPLAY-STRING . PLIST)."
  (let ((posts (my-blog-posts)))
    (mapcar (lambda (o)
              (my-blog-format-for-completion
               (append o
                       (my-blog-post-info-for-url (alist-get 'source_path o)
                                                  posts))))
            (seq-uniq
               (my-org-db-v3-to-emacs-rag-search input 100 "%static-blog%")
               (lambda (a b) (string= (alist-get 'source_path a)
                                      (alist-get 'source_path b)))))))

It uses some functions I defined in other parts of my config:

When I explored emacs-rag-search, I also tried hybrid search (vector + full text). At first, I got "database disk image is malformed". I fixed this by dumping the SQLite3 database. Using hybrid search, I tended to get less-relevant results based on the repetition of common words, though, so that might be something for future exploration. Anyway, my-emacs-rag-search and my-emacs-rag-search-hybrid are in the emacs-rag-search part of my config just in case.

Along the way, I contributed some notes to consult.el's README.org so that it'll be easier to figure this stuff out in the future. In particular, it took me a while to figure out how to use :lookup #'consult--lookup-cdr to get richer information after selecting a completion candidate, and also how to use consult--dynamic-collection to work with slower dynamic sources.

Quick thoughts and next steps

It is kinda nice being able to look up posts without using the exact words.

Now I can display a list of blog posts that are somewhat similar to what I'm currently working on. It should be pretty straightforward to filter the list to show only posts I haven't linked to yet.

I can probably get this to index the text versions of my sketches, too.

It might also be interesting to have a multi-source Consult command that starts off with fast sources (exact title or headline match) and then adds the slower sources (Google web search, semantic blog post search via org-db-v3) as the results become available.

I'll save that for another post, though!

View org source for this post

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

-1:-- Playing around with org-db-v3 and consult: vector search of my blog post Org files, with previews (Post Sacha Chua)--L0--C0--2025-10-29T00:32:24.000Z

Irreal: Piping In And Out Of Emacs Buffers

A couple of weeks ago, I wrote about piping Eshell output to a buffer. It’s a cute trick but it only works in Eshell. It turns out you can do better.

iLemming has a video on piping in and out of an Emacs buffer even in a normal shell. He begins by showing how to accomplish input redirection within Eshell. That’s not supported by Eshell itself so it requires a supporting eshell function—that iLemming calls b​—to work.

The real juice of the video is making this work in a normal—that is, non-Eshell— shell. That requires another function, mxp, this time a shell script. If you watch the video or follow the mxp link, you’ll see several examples of mxp in use. It’s really quite flexible.

All of this clever and the code is worth taking a look at to see how you might do this type of thing. Still, I don’t see how I would use this capability. I could probably make up some fake application for it but it’s hard to imagine any realistic use. Of course, that’s probably due to my lack of imagination and I’m sure some of you will jump in to educate me.

-1:-- Piping In And Out Of Emacs Buffers (Post Irreal)--L0--C0--2025-10-28T16:23:31.000Z

Christian Tietze: Sharpening the Saw with Emacs

I’m using Emacs for some time now. As is custom, I move more and more of my computing, writing, and scripting into Emacs – becaue I learned to love the writing experience and through customization made it feel like it’s my own.

Now that Emacs is a comfy place, I tend to just hang out there from time to time and tinker with things.

In a woodworking workshop, this would be the time for rearranging, cleaning, and sharpening tools; time to organize the workshop, reflect on things I’ve crafted in the past, and how to improve the workshop; time to ponder how to approach the next project, and clean up after finished ones.

Stephen Covey, in his “7 Habits”, made the woodworking metaphor of “Sharpening the Saw” a prominent insight: You need to perform in your job, be productive, and do excellent work, but for that you also need time to work on your tools, not just with them. A dull saw won’t cut well.

Some of my interpretations of that metaphor:

  • It cannot all be just about the performance. You also need downtime.
  • If you only run as fast as you can, you’ll lose track of where you need to go.
  • In meta-work, there’s potential for meditative practice, reflection, and joy.
  • It’s a good sign that you want to improve the way you work, and not just “do the job” and then forget about it.

I’m blessed with a “day job” that I enjoy doing, and which is infinitely malleable, because all I do happens in front of a computer. That’s a work environment that you can tweak to whatever desires and circumstances. Here, Emacs does an incredible job: it offers a weird stock-standard experience, but helps you manifest a truly personalized computing environment on any machine. Windows, Linux, Mac – Android tablets, toasters, smart TV’s, you can get it to run anywhere and everywhere, take it with you when you change jobs, hobbies, or your phone. It stays with you as the rest of technology changes and moves in and out of fashion.

Spending time tinkering with Emacs and personalizing the computing environment is time spent well. It is time I can invest in my computing future.

I wouldn’t have imagined that switching my primary text editor all those years ago would result in a newfound sense of computing freedom. Freedom from proprietary shackles, yes; but also freedom to do things I want to do in a way I want to do them. To write in a particular way; to work with code and text and images and files and servers in a particular way.

Maintaining my Emacs configuration and setup equals maintaining my computer.

On lazy evenings (which I don’t have a lot of with a daughter and all), I can invest half an hour on something that got on my nerves during the day so that my future self will be better off. Maybe even more efficient, more productive, but that’s not always the point. Sometimes it’s just about removing dust so that it looks neater and feels nicer to use.

Oten, this means I’ll tinker with Emacs Lisp. For example, I recently wrote a short function to convert selected files in Dired to .webp for a better and easy general-purpose compression of images for all my web projects. Makes working with many files I touch every day feel less clunky. I’m a slightly happier person now.

Often, it also means I’m tinkering on content I work on within Emacs. Clean up my org-mode files so that the next day won’t look and feel as cluttered. (I’m a terrible hoarder. And by default, my info management will degrade with clutter and noise, and I just get used to living in a pile of digital junk.)

Sometimes, it can be both coding and organizing – to tweak a bit of code that helps me filter or file away content in a nicer way. To find outdated tasks and delete them.

It’s both carthatic to know that I improved my overall computing situation, and it’s a source of joy to do it in this particular way. There’s joy in the process and outcome both. I did find that sharpening my chisels and blades has a similar effect – only with Emacs, because I like computer stuff even more, the tool maintenance is so much more fun.


Hire me for freelance macOS/iOS work and consulting.

Buy my apps.

Receive new posts via email.

-1:-- Sharpening the Saw with Emacs (Post Christian Tietze)--L0--C0--2025-10-28T07:50:55.000Z

TAONAW - Emacs and Org Mode: Emacs and mental challanges

As part of a trip to see her friend, my mom went to a show of Porsche cars last week. This is a group of enthusiastic Porsche owners from different years. One of the stories she shared was about a proud Porsche owner who drives in countries that require the driver’s seat on the right (I’m assuming the UK or Ireland?) The driver, instead of abandoning his Porsche, had his beloved car set up with an adjustable steering wheel that can shift to the right or left side of the driver’s seat.

Emacers already know where this is going. We are all, in our own way, drivers just like this guy. The difference, of course, is that we drive Emacs, not a Porsche (though I’m sure there are a few of you out there who drive both!). I find this story inspiring because the laws that dictate where the driver should sit in the car are imposed. There’s nothing the driver could do about the law itself, so they came up with their own solution to work with the law in a clever way. Again… Emacs.

Emacs is not easy to drive in 2025. It has a steep learning curve, especially if you don’t have a good computer background. The other big problem is the outside restrictions. This blog is riddled with challenges I have with Emacs and different workarounds I came up with. I think this post I wrote earlier this year summarizes it well. To recap quickly: my work environment forces me to use applications that don’t play nice with Emacs. The biggest issue I have is with emails (only Outlook is allowed), but other cloud-based software is also problematic, usually because the only interaction with it is through the browser.

There are several community solutions for these issues. One of those is Emacs Everywhere, which I need to try to play with again (the issue I have there is creating a keyboard shortcut invoking a terminal command in macOS, which proved more challenging than I thought it would be), and there are more. But there’s also a bigger issue: there are plenty of new shiny apps out there, and next to Emacs, integration is always easier and nicer. Some of those, if I go deep into the rabbit hole, survive a day or two, even a weekend - but usually I go back to Emacs gasping for air. The overall issue with other apps is that they work nice, as long as you play by their rules and restrictions. As soon as you need to customize something, you’re out of luck. They are usually also all cloud-based, which is something else I don’t like. I know I’m old-fashioned, but I like that the cloud is there as a secondary place when I need it, not forced on me to use.

Some notable examples I visited again recently are both Apple tools: Notes and Journal. Notes got a few more tweaks, making it a useful as a personal database. I love how you can scan documents directly into the App, which works seemingly with the iPhone, and I love how I can now use it on my Apple Watch to check off items when I go grocery shopping. But I would never trust Apple to store my private notes on their servers. Journal has the same issue. The app itself matured nicely, with the addition of a macOS app. It comes with useful reminders, a map to see where entries were entered, a timeline, and a surprisingly good export option to HTML, including all the entries. But it’s also a good reminder of my point above: the date format.

I don’t like the US date format, especially in my personal notes. Org-mode automatically writes dates in a yyyy-mm-dd format, which has always made more sense to me (by the way, if you know a good app that can do that for the top menu in macOS, let me know. I’m surprised Apple doesn’t include that option natively. I’ve tried to change the region and play with the clock options in the past.)

The mindset that long-time Emacs users share with the Prosche driver is what got us into Emacs in the first place. We need things working out our way. In my case, I always liked checklists and bullet points, and I used several tools to help me organize things until I discovered Orgzly, and from there, org-mode and Emacs. I mentioned several times before that I owe my current professional successes (which include promotions at work, beyond just staying sane in a pretty chaotic environment) to org-mode, but that’s not exactly true. It’s the other way around: Emacs org-mode is a tool that enables me to use my mind the way I need to use it to work out information. I believe that if there were other tools that allowed me to change things as much as I can in Emacs, I would work with those too. But, in the age of the cloud, the opposite is true. Workflows are imposed, and customization to fit personal needs usually ends up being limited to dark and light themes.

Emacs is a rare tool that allows you to do whatever you want if you just look under the hood and tweak it to your needs. There aren’t many other programs like it, and I suspect that for most people, they are not needed. But for someone like me, adjusting to other tools doesn’t work well. And it’s not a good thing. I tried to force it a couple of times; believe me, if I were happy with Outlook, OneNote, and SharePoint, my work life would be much simpler. But I get disorganized, and I can’t work without my tools. If I like tinkering with something like Emacs, it’s not just for fun: if I don’t, I’m going to “glitch” until I fix it. It’s a battle uphill, a challenge—always was, and always will be. The benefit, however, is that it keeps me on my feet, and when I get something that works for me, it really works. Better than any other easy solution offered.

-1:-- Emacs and mental challanges (Post TAONAW - Emacs and Org Mode)--L0--C0--2025-10-27T20:32:52.000Z

Marcin Borkowski: Org mode burst timer

Preview: Org mode has two built-in timers – the “relative timer” (which is basically a stopwatch – it starts with 0 and counts up), useful for taking meeting minutes with an indication of when things were discussed, and a “countdown timer” (which is, well, a countdown timer – you tell it a duration, it counts down from it, and rings a bell when it gets to zero). What I sometimes miss is the following feature. I’d like to have some kind of timer which would tell me when a given amount of time passed, but then it would keep running. For instance, let’s assume that I want to write this blog post for at least 25 minutes, but also measure the time I spend doing it even if I keep writing for longer.
-1:-- Org mode burst timer (Post Marcin Borkowski)--L0--C0--2025-10-27T15:20:50.000Z

Sacha Chua: 2025-10-27 Emacs news

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

View org source for this post

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

-1:-- 2025-10-27 Emacs news (Post Sacha Chua)--L0--C0--2025-10-27T14:04:01.000Z

I found a potentially useful package that creates a visual calendar inside Emacs. It seems to be mostly abandoned, at least in its current form. It now requires ugly workarounds in order to work.

Does anyone know something like it that works currently?


Update: From the comments, I’m learning that taking the requirements for compat seems to be the official fix. This is a pretty nice package. I’m exploring it more in depth, and I might change some workflows I have accordingly. I find it amusing that I stumbled into it by chance, as I was writing my other post.

-1:--  (Post TAONAW - Emacs and Org Mode)--L0--C0--2025-10-27T13:57:33.000Z

tusharhero: GNU Emacs needs a virtual keyboard

~929 words. ~4 minutes.

I mean this more generally as in everywhere GNU Emacs is available, but especially the recent Android port.

If you are like most people, you have probably had to edit text on a mobile phone. And then you must be aware of how the virtual keyboard is not just used for entering characters into the text area, but it in fact assists the user while editing the text, through auto completions, cursor movement through the keyboard, and so forth and so on.

Now I would guess most of you haven't tried GNU Emacs on Android for any extended amount of time, but from my time seriously using it on Android (for the past 3 months, mostly for Org-Agenda and friends). I can say that it is actually pretty useful(and able), and IMO is the best org client on Android. The trick to using it on Android is not disabling the GUI elements (like the menu-bar, tool-bar, and the likes), these elements are really useful and you can do many complex editing operations using them, you can even go further, by creating your own menu-bar items, tool-bar icons, etc.

Though, one could say this is generally true for Emacs, too many people ask beginners to disable the helpful menu-bar and tool-bar.

There is also an especially useful GUI element called the modifier-bar-mode,

Toggle display of the modifier bar.

When enabled, a small tool bar will be displayed next to the tool
bar containing items bound to
‘tool-bar-event-apply-control-modifier’ and its related commands,
which see.

This is a global minor mode.  If called interactively, toggle the
‘Modifier-Bar mode’ mode.  If the prefix argument is positive, enable
the mode, and if it is zero or negative, disable the mode.

If called from Lisp, toggle the mode if ARG is ‘toggle’.  Enable the
mode if ARG is nil, omitted, or is a positive number.  Disable the mode
if ARG is a negative number.

To check whether the minor mode is enabled in the current buffer,
evaluate ‘(default-value 'modifier-bar-mode)’.

The mode’s hook is called both when the mode is enabled and when it is
disabled.

(fn &optional ARG)

What it does is expose the Ctrl, Shift, Meta, Alt (Yes, they are different.), Super, and Hyper keys as buttons on this modifier-bar. This is very similar to what Termux does. And also very useful (though I still use the unexpected keyboard in conjunction with this).

The need for a full fledged keyboard is further demonstrated by this development. The Emacs virtual keyboard would be a natural extension of the idea.

Emacs' virtual keyboard could be made very dynamic, changing its keys/buttons according to the mode we are in. For example, when we are in Org-Mode, we could have specialized keys for it!


This is not something that has not been tried before, take a look at calc-keypad,

Invoke the Calculator in "visual keypad" mode.
This is most useful in the X window system.
In this mode, click on the Calc "buttons" using the left mouse button.
Or, position the cursor manually and do M-x calc-keypad-press.

(fn &optional INTERACTIVE)

This is how it looks currently,

----+----+--Calc---+----+----1
FLR |CEIL|RND |TRNC|CLN2|FLT |
----+----+----+----+----+----|
 LN |EXP |    |ABS |IDIV|MOD |
----+----+----+----+----+----|
SIN |COS |TAN |SQRT|y^x |1/x |
----+----+----+----+----+----|
  ENTER  |+/- |EEX |UNDO| <- |
-----+---+-+--+--+-+---++----|
 INV |  7  |  8  |  9  |  /  |
-----+-----+-----+-----+-----|
 HYP |  4  |  5  |  6  |  *  |
-----+-----+-----+-----+-----|
EXEC |  1  |  2  |  3  |  -  |
-----+-----+-----+-----+-----|
 OFF |  0  |  .  | PI  |  +  |
-----+-----+-----+-----+-----+

Here, they just look like regular text, but maybe using Emacs' buttons would look better, the task is making it standardized and easy to add, like how Org-Mode does its own ad hoc transient-like menus, but now with transient, it is easier to make such menus and all the menus look similar, so the same muscle memory is utilized in of all of these menus coming from different packages.

When Emacs has its own toolkit (some day I hope), the virtual keyboard would get even more powerful!


What if we also made it possible for Emacs to be used as the keyboard on Android, so that it is possible to edit texts using Emacs on any text area anywhere on the operating system? This would be analogous to emacs-everywhere or tinee on GNU/Linux systems, though would probably be better integrated with the rest of the operating system.


All these are just thoughts I have had for a while, that I finally decided to put on buffer. I don't have plans on working on this in the near future, but if someone else is interested I would love to see it being realized.

-1:-- GNU Emacs needs a virtual keyboard (Post tusharhero)--L0--C0--2025-10-27T04:00:00.000Z

Alvaro Ramirez: time-zones now on MELPA. Do I have your support?

A little over a week ago, I introduced time-zones, an Emacs utility to easily check city times around the world. Today, I'm happy to report, the package has been accepted into MELPA.

It's been wonderful to see how well time-zones was received on Reddit.

✓ You asked for MELPA publishing and I delivered.

✓ You asked for DST display and I delivered.

✓ You asked for a UTC picker and I delivered.

✓ You asked for UTC offset display and I delivered.

✓ You asked for Windows support and I delivered.

✓ You asked for help and bug fixes and I delivered.

Will you make the work sustainable?

Bringing features and improving our beloved text editor takes time and effort. time-zones isn't my first package, I've also published a bunch of Emacs packages. Will you help make this work sustainable?

-1:-- time-zones now on MELPA. Do I have your support? (Post Alvaro Ramirez)--L0--C0--2025-10-27T00:00:00.000Z

Philip Kaludercic: Ini-style Emacs Configuration Files?

I while back I wrote up a sketch to interpret Ini-style configuration files for Emacs. Here I want to present and discuss the idea briefly. Syntax For those wondering how a “ini-style init file” looks like (I certainly would), I translated parts of my init.el into a syntax that ini.el can handle, to give an idea of how these files look like: enable inhibit-startup-screen ...abridged...
-1:-- Ini-style Emacs Configuration Files? (Post Philip Kaludercic)--L0--C0--2025-10-26T19:03:33.000Z

Irreal: Oil.el

It’s a lazy Sunday and there’s nothing much going on in the Internet to interest Irreal or its readers so I’m offering you this little nugget that popped up this morning. Oil.el is a tiny package that brings the functionality of Oil.nvim to Emacs.

The idea is that you can batch create files in a given directory by simply listing their names, one per line, into the app. When you’re done, simply type Ctrl+c Ctrl+c and the files are created. Or, you can cancel the operation with Ctrl+c Ctrl+k.

It’s not clear to me why this app is as popular as it seems to be—at least in the Vim world. It’s not that there’s anything wrong with the app itself, I just don’t see the need for it, especially given the existence of Dired. Nonetheless, Emacs is all about letting you have it your way so if Oil’s workflow appeals to you, its existence is a good thing.

The package is not (yet?) on Melpa but you can download it directly from GitHub if you’re interested. I’m guessing that this app will be mostly of value to refuges from Vim who are used to its Vim analog. Regardless, it’s there for you if you’re interested.

-1:-- Oil.el (Post Irreal)--L0--C0--2025-10-26T16:09:02.000Z

Protesilaos Stavrou: Prot Asks: Maxim about writing, thinking, criticism, narratives, and productivity

Raw link: https://www.youtube.com/watch?v=7No-ueqLmkw

In this 2-hour video, I talk with Maxim about the themes of writing and thinking, as well as productivity at-large. Maxim is a professor of linguistics at a university in Russia. He has a PhD in philology.

The first point of interest we cover is Emacs. Maxim uses Emacs for taking notes, keeping track of tasks, and staying organised. Part of this workflow involves the org-roam package, which is an excellent tool for maintaining a note-taking system. The other part is the Org agenda, which in Maxim’s case helps maintain a macro view of the ongoing projects.

I then ask about Maxim’s work and learn about the distinction between linguistics and philology. In this context we discuss attitudes towards reading and writing. We explore how the education system assumes that if you are a local you already are competent in the local tongue, which is not necessarily true. Maxim teaches “effective writing”, which we explore in some further depth.

One of the topics we delve into is about the benefits of writing. This is about keeping a journal or publishing posts on a blog. I also share my own experiences in this regard, as someone who publishes a lot. Writing is a medium through which one may elucidate their thoughts and thus understand their own ideas better.

A blog, in particular, is like journaling on hard mode. This is because of the potential for criticism. We talk about what criticism does, how to think of yourself as a writer/thinker, and ways to approach phenomena such as trolling.

Throughout our exchange we make references to the human condition and narratives. We discuss the function of dreams, of fiction, and about learning from experiences that are not necessarily specific to the facts of one’s condition. Maxim tells me about his endeavours with blogging as well as how he likes to follow the stories of athletes.

Another thread that runs through our talking points is that of productivity and how it is important to keep one’s own experience and needs in perspective.

Link to Maxim’s page

The content is in Russian: https://t.me/light_higher

About “Prot Asks”

In this new video series, I talk to anybody who is interested to have a video call with me (so do contact me if you want!). The topics cover anything related to Emacs, technology, and life in general. More here: https://protesilaos.com/prot-asks/.

-1:-- Prot Asks: Maxim about writing, thinking, criticism, narratives, and productivity (Post Protesilaos Stavrou)--L0--C0--2025-10-26T00:00:00.000Z

Irreal: Bending Emacs 4: Batch Renaming Of Files

Álvaro Ramírez has a new video up. This one, Bending Emacs 4, demonstrates several ways of batch renaming files. The secret sauce in most of these methods is the ability of the Dired buffer to become writable and have the changes reflected in the underlying file system. Every time I use it, it seems like magic.

Ramírez’s video shows several ways of performing bulk renamings in the Dired environment. Probably the easiest—or the most natural to me—is simply using a keyboard macro. For instance, if you have a directory full of files ending in .org and want them all to end in .txt, you simply start recording a macro, change the first file, move to the next line, and close the macro. Then you can run the macro on the rest of the buffer to rename all the files. After the renaming, all you need do is type C-c C-c to instantiate the changes into the file system.

Ramírez’s favored way of making the changes is to use Magnor Sveen’s wonderful Multiple Cursors package. It’s a bit more flexible than a keyboard macro because you have finer control over which lines will be changed. Once you’ve got the desired files marked, you simple make the change on one and they are all affected.

The video is only 6 minutes, 42 seconds long so it should be easy to fit in. Ramírez even includes a DWIM command line method of renaming the files. The nice thing about using Dired is that you can arrange for Git to be aware of the renaming. Take a look at the video for the details.

-1:-- Bending Emacs 4: Batch Renaming Of Files (Post Irreal)--L0--C0--2025-10-25T15:55:05.000Z

Andros Fenollosa: Why your social.org files can have millions of lines without any performance issues

As Org Social grows, users follow more feeds, and individual social.org files accumulate hundreds of posts over time. Traditional approaches that download entire feeds sequentially create two major bottlenecks:

  1. Bandwidth waste: Downloading complete files when users only need recent posts
  2. Time inefficiency: Sequential downloads that block the user interface

This article explores how Org-social.el 2.3+ (Official client) solves both problems with a sophisticated combination of concurrent queue processing and HTTP Range-based partial fetching while maintaining complete compatibility with all servers.

The Challenge

flowchart TB
    A[User Opens Timeline] --> B[20 Feeds to Download]
    B --> C[Traditional Approach: Sequential Downloads]
    C --> D[Feed 1: 27KB 150 posts]
    D --> E[Feed 2: 15KB 80 posts]
    E --> F[Feed 3: 12KB 60 posts]
    F --> G[... 17 more feeds]
    G --> H[Total: ~300KB and ~1500 posts]
    H --> I[Filter to last 14 days]
    I --> J[Actually needed: ~10 posts=first page]

    style C fill:#ffcccc,color:black
    style H fill:#ffcccc,color:black
    style J fill:#ccffcc,color:black

Downloading 300KB and processing 1500 posts to get 10 posts... It is not good!

Optimization

Org-social.el implements a sophisticated three-layer approach:

Layer 1: Concurrent Queue Processing

A process queue is a data structure that manages tasks to be executed. In Org Social, each feed to download is added to the queue as a pending task. The system then processes these tasks concurrently (multiple at the same time) using a worker pool—a limited number of threads that execute downloads in parallel.

This smart queue system manages parallel downloads without overwhelming system resources.

flowchart LR
    A[Feed Queue] --> B[Worker Pool Max 20 concurrent]
    B --> C[Worker 1 Feed A]
    B --> D[Worker 2 Feed B]
    B --> E[Worker 3 Feed C]
    B --> F[...]
    B --> G[Worker 20 Feed T]

    C --> H{Done?}
    D --> H
    E --> H
    G --> H

    H -->|Yes| I[Process Next Pending Feed]
    H -->|Error| J[Mark Failed, Continue]

    I --> B
    J --> I

    style B fill:#e1f5ff,color:black
    style H fill:#fff4e1,color:black
    style I fill:#ccffcc,color:black

Key Features:

  • Configurable concurrency: org-social-max-concurrent-downloads (default: 20)
  • Non-blocking threads: Each download runs in a separate thread
  • Automatic recovery: Failed downloads don't block the queue
  • Smart scheduling: New downloads start immediately when slots free up

Layer 2: HTTP Range-Based Partial Fetching

HTTP has a built-in feature that allows downloading only specific parts of a file using the Range header. When a client sends a request with Range: bytes=0-999, the server responds with just the first 1000 bytes of the file instead of the entire content. This capability is commonly used for video streaming and resumable downloads, but it can also be used to paginate files—downloading them in chunks rather than all at once.

Instead of downloading entire social.org files, Org Social uses HTTP Range requests to fetch only what's needed: the header section and recent posts.

This system is not compatible with all providers. While most traditional web servers (Apache, Nginx, Caddy) support HTTP Range requests natively, some hosting platforms have limitations:

  • Cloudflare CDN: Does not provide Content-Length or Content-Range headers, making it impossible to determine file size or download specific byte ranges. The system automatically falls back to downloading the complete file and filtering client-side.

  • Codeberg.org: Implements aggressive rate limiting when multiple Range requests are made in quick succession. When HTTP 429 (Too Many Requests) is detected, the system falls back to a full download without filtering to avoid being blocked.

  • GitHub Raw Content: Provides proper HTTP Range support and works optimally with partial downloads.

The system detects these limitations automatically and adapts its strategy to ensure 100% compatibility across all hosting platforms.

sequenceDiagram
    participant C as Client
    participant S as Server
    participant F as social.org (27KB, 150 posts)

    Note over C,F: Step 1: Find Header
    C->>S: Range: bytes=0-999
    S->>C: First 1KB (headers)
    Note over C: Found "* Posts" at byte 800

    Note over C,F: Step 2: Get File Size
    C->>S: Range: bytes=0-0
    S->>C: Content-Range: bytes 0-0/27656
    Note over C: Total size: 27656 bytes

    Note over C,F: Step 3: Fetch Recent Posts
    C->>S: Range: bytes=26656-27655
    S->>C: Last 1KB (recent posts)

    C->>S: Range: bytes=25656-26655
    S->>C: Previous 1KB
    Note over C: Found post older than 14 days

    Note over C,F: Result: Downloaded 3KB instead of 27KB

Algorithm:

  1. Header Discovery (bytes 0 → forwards)
  2. Download the first 1KB chunk (bytes 0-999)
  3. If * Posts is not found, download the next 1KB chunk (bytes 1000-1999)
  4. Continue downloading subsequent chunks until * Posts is found
  5. Typical header size: 500-1500 bytes

  6. Backward Post Fetching (end → backwards)

  7. Start from the end of the file (most recent posts)
  8. Download 1KB chunks moving backwards
  9. Parse each post's :ID: property (e.g., :ID: 2025-10-24T10:00:00+0200)
  10. Stop when reaching posts older than org-social-max-post-age-days (default: 14 days)

  11. Date Filtering

  12. Parse post IDs (RFC 3339 timestamps)
  13. Keep only posts ≥ start date
  14. Discard older posts without downloading

Trick for Range Support Detection

The system sends a test request with the Range: bytes=0-0 header to check if the server responds with Content-Range or Accept-Ranges: bytes headers, indicating Range support.

Edge Cases and Fallbacks: Compressed Content

Servers using gzip compression (e.g., Caddy) report compressed sizes:

Problem: HEAD request returns compressed size, but content arrives uncompressed

Solution: Use a Range request (bytes=0-0) for size detection instead. The server responds with Content-Range: bytes 0-0/TOTAL where TOTAL is the actual uncompressed file size.

Layer 3: UI Pagination

Even after downloading only recent posts, rendering all of them at once would overwhelm Emacs. The Org Social UI uses widgets to create an interactive interface with buttons, images, and formatted text. Each widget consumes memory and processing power.

To keep the interface responsive, the system implements pagination that displays only 10 posts per page. This means:

  • When a user opens the timeline, only the first 10 most recent posts are rendered
  • Images, avatars, and interactive widgets are created only for these 10 visible posts
  • The remaining downloaded posts stay in memory but aren't rendered
  • Users can navigate to the next page, which then renders the next 10 posts
flowchart LR
    A[Downloaded Posts: 50] --> B[Page 1: Render 10 posts]
    A --> C[Page 2: 10 posts in memory]
    A --> D[Page 3: 10 posts in memory]
    A --> E[Page 4: 10 posts in memory]
    A --> F[Page 5: 10 posts in memory]

    B --> G[User sees: 10 posts with widgets & images]

    C -.->|User clicks Next| H[Render next 10 posts]

    style A fill:#e1f5ff,color:black
    style B fill:#ccffcc,color:black
    style G fill:#d5ffe1,color:black
    style H fill:#ffe1cc,color:black

Emacs widgets and image rendering are resource-intensive. Rendering 50 posts with avatars and buttons could slow down the editor. By rendering only 10 at a time, the UI stays fast and responsive regardless of how many posts were downloaded.

This is the final optimization layer: even if your social.org has 10,000 posts, and you download 50 recent ones, you only render 10 on screen. The rest wait in memory until needed.

Performance Benchmarks

The following table shows how the system scales with different feed sizes, assuming an average post size of 250 bytes and a 14-day filter (capturing approximately 20-30 recent posts):

Scenario Total Posts Full File Size With Partial Fetch (14 days) Description
Empty feed 0 ~1 KB ~1 KB Only headers downloaded
New user 1 ~1.5 KB ~1.5 KB Single post, no optimization needed
Light user 10 ~3.5 KB ~3.5 KB All posts fit in 14-day window
Regular user 100 ~26 KB ~8 KB Headers + ~30 recent posts
Active user 1,000 ~250 KB ~8 KB Headers + ~30 recent posts
Power user 10,000 ~2.5 MB ~8 KB Headers + ~30 recent posts

Key insight: Once a feed exceeds ~100 posts, partial fetching maintains consistent download sizes (~8 KB) regardless of total feed size. A feed with 10,000 posts downloads the same amount of data as one with 1,000 posts.

Tuning Recommendations

Users can customize two main parameters:

  • org-social-max-concurrent-downloads: Maximum parallel downloads (default: 20)
  • org-social-max-post-age-days: Maximum age of posts to fetch in days (default: 14)

So...

  • Fast connection + many feeds: Increase to 30 concurrent
  • Slow connection: Decrease to 10 concurrent
  • Large feeds + limited bandwidth: Decrease max-post-age-days to 7
  • Small feeds: Set max-post-age-days to nil (no optimization needed)

Conclusion

The three-layer optimization approach (concurrent queue processing, HTTP Range-based partial fetching, and UI pagination) provides a significant bandwidth optimization on large feeds with date filtering and non-blocking UI. This architecture positions Org Social to scale efficiently as both individual feeds and follower counts grow, while maintaining the simplicity and decentralization that make Org Social unique.

Your social.org can have millions of lines because:

  1. Only recent posts are downloaded (14 days by default)
  2. Downloads happen in parallel without blocking
  3. Only 10 posts are rendered on screen at once

Enjoy it!

Technical References

-1:-- Why your social.org files can have millions of lines without any performance issues (Post Andros Fenollosa)--L0--C0--2025-10-25T07:02:41.000Z

Emacs APAC: Announcing Emacs Asia-Pacific (APAC) virtual meetup, Saturday, October 25, 2025

This month’s Emacs Asia-Pacific (APAC) virtual meetup is scheduled for Saturday, October 25, 2025 with BigBlueButton and #emacs on Libera Chat IRC. The timing will be 1400 to 1500 IST.

The meetup might get extended by 30 minutes if there is any talk, this page will be updated accordingly.

If you would like to give a demo or talk (maximum 20 minutes) on GNU Emacs or any variant, please contact bhavin192 on Libera Chat with your talk details:

-1:-- Announcing Emacs Asia-Pacific (APAC) virtual meetup, Saturday, October 25, 2025 (Post Emacs APAC)--L0--C0--2025-10-24T18:57:41.000Z

Irreal: A Simple Emacs Dashboard

Randy Ridenour, whom I’ve written about before, has an interesting post on customizing the Emacs Dashboard. The Dashboard is something that appears when Emacs starts. It typically shows recently visited files and the current agenda items.

It’s configurable—of course, it’s Emacs—but Ridenour wasn’t happy with the default configurations. Emacs being Emacs, it was pretty easy to get things just the way he liked them. Part of that was displaying the agenda in a the usual way rather than just a list of activities. In particular, he like having the current time displayed—the way it is in grid view—and even arranged for it to appear in red so that it would stand out. He also arranged to have the agenda updated every minute so the time would always be up to date.

In addition to the agenda, he has a list of links that he wants to appear in the Dashboard so he has an Org file with a table of those links that he imports and then activates the links. At the end, he has a Dashboard with exactly the information he wants.

To be honest, I’ve never seen the point of Emacs Dashboards. My Emacs is always running so startup Dashboards don’t make any sense to me. I know you can start them whenever you like but, again, I’ve never seen the point. When I start Emacs, the first thing I do is start the agenda and mu4e. I could easily automate that but it’s so easy to start them by hand and I start Emacs so infrequently that it’s not worthwhile.

In any event, if you’re one of the many people who do like an Emacs Dashboard, Ridenour’s post may have some ideas that you can use.

Update [2025-10-24 Fri 14:12]: Added link.

-1:-- A Simple Emacs Dashboard (Post Irreal)--L0--C0--2025-10-23T15:22:17.000Z

Kana: Using Emacs Org-mode As My Package Manager

I install random packages from time to time (using Arch Linux, by the way), maybe to try out things, to solve an issue at hand or as an implicit dependency to my Emacs config or other scripts. And it was a pain having to keep in mind which is for which.

Then, I started keeping notes for them and automated a bunch of note keeping. And now, I have an Org-mode note file effectively serving as a minimal wrapper for the pacman package manager.

Read more… (5 min remaining to read)

-1:-- Using Emacs Org-mode As My Package Manager (Post Kana)--L0--C0--2025-10-23T03:04:34.000Z

Alvaro Ramirez: Bending Emacs - Episode 4: Batch renaming files

I'm now a few weeks into my Bending Emacs series. Today I share a new episode.

Bending Emacs Episode 4: Batch renaming files

In this video, I show a few ways of batch renaming files.

The covered flows are:

Want more videos?

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

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

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

Make it all sustainable

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

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

-1:-- Bending Emacs - Episode 4: Batch renaming files (Post Alvaro Ramirez)--L0--C0--2025-10-23T00:00:00.000Z

Randy Ridenour: A Simple Emacs Dashboard

A Simple Emacs Dashboard

(October 22, 2025)

Emacs Dashboard is an elegant start page for Emacs that displays projects, recent files, agenda items, etc. It’s very customizable, but not quite in the way that I would like. I do like having a dashboard as my starting page, but I want something that displays the usual agenda view, not just a list of events. This is mainly because I like having a visual representation of the relation between the current time and my next appointment. I first define a function that opens the agenda for today and deletes other windows in the frame. This is assigned to s-d to quickly clear the screen of anything displayed and show the agenda. To display it without deleting other windows, just use the standard C-c a d

 ( defun  agenda-home ()
  ( interactive)
  (org-agenda-list 1)
  (delete-other-windows))

Then, I make sure that new frames displayed this when created.

 (add-hook 'server-after-make-frame-hook #'agenda-home)

This function refreshes the agenda. It’s run every minute. That’s really overkill, but 34 years in the Army made me anal about accurate times.

 ( defun  refresh-agenda-periodic-function ()
   "Recompute the Org Agenda buffer(s) periodically."
  ( ignore-errors
    ( when (get-buffer  "*Org Agenda*")
          ( with-selected-window (get-buffer-window  "*Org Agenda*")
            (org-agenda-redo-all)))))

 ;;  Refresh agenda every minute.
(run-with-timer 60 60 'refresh-agenda-periodic-function)

The line used to designate the current time is a bit too long by default. I didn’t like how it wrapped when narrowing the window.

 ( setq org-agenda-current-time-string  "now - - - - - - -")

Then change the color to something more noticeable.

 (custom-set-faces
 '(org-agenda-current-time ((t ( :foreground  "red")))))

Now, to make the dashboard links. For that, I use an org file that just contains a table. Each cell contains a link to a directory, file, runs some Elisp, etc. After inserting the file contents, then activate all of the links, that is, make them “clickable.”

 ( defun  rlr/agenda-links ()
  (end-of-buffer)
  (insert-file-contents  "/Path to Org Directory/agenda-links.org")
  ( while (org-activate-links (point-max))
    (goto-char (match-end 0)))
  (beginning-of-buffer))

(add-hook 'org-agenda-finalize-hook #'rlr/agenda-links)

I don’t like using the mouse, so make sure that pressing enter will work when the point is on the link.

 ( setq org-return-follows-link t)

This avoids having to confirm that the links that run Elisp are safe. I name them all with my initials to make it easy.

 ( setopt org-link-elisp-skip-confirm-regexp  "rlr.*")

The result is this:

2025-agenda-screenshot.png

Tagged: Emacs

-1:-- A Simple Emacs Dashboard (Post Randy Ridenour)--L0--C0--2025-10-22T10:28:00.000Z

Michal Sapka: New engine, who dis?

So, this has happened. Again. I rewrote my entire static site renderer from scratch and what you're seeing is "msite 2.0". It should differ very slightly from what was here yesterday, but with time, I want to make some cool things. Those will be revealed in time, but for now: the meat. I know you shiver with antici...

As you may have read, I moved from Emacs back to Vim. It's not that I don't enjoy Emacs (on the contrary!), but I don't love Elisp enough to give up on shell scripts. OR rather: I don't have enough willpower to master it right now. Also, modal editing is still very close to my heart. So, the first change is this: posts are files, once more. In v1 Emacs was UI over sqlite db, but now DB is used only for fast building of index. Everything else gets data from the files (I call this format "msite-flavored html" and I find it cute).

As a bonus, I have decided to make this my first python adventure. I am very well surprised! The code is as simple as it gets, but the language proved itself very pleasant. I don't even mind the indentations, as it was very easy to convince Vim to handle those. Also: imports. Explicit imports are the stuff dreams are made of.

When writing the previous version, both in Elisp in ruby code, I create completely wrong abstractions. This made making any change a chore. And you know what they say: why fix when you can rewrite?

Ergo: the logic now lives in python, and my editing happens in Vim. I am as surprised as you are.ID

Note, there may be errors. Don't be alarmed!

I am now a self-certified Python developer.

...pation

-1:-- New engine, who dis? (Post Michal Sapka)--L0--C0--2025-10-21T22:41:53.000Z

Irreal: Rendering SVG Images In Org Generated HTML

I’ve recently discovered to my surprise that rendering an SVG image in HTML from Org mode is difficult or at least poorly documented. It comes as news to me because the images that I want to render are always JPEGs so I’ve never stumbled on the problem.

It turns out that there are two solutions. The first, from Norman Walsh, converts the Org mode link to the SVG file into an HTML div containing the image. Unfortunately, Walsh doesn’t give any details.

The second solution, from tusharhero, leverages the Org Babel interface to make and display an SVG image. I like his solution better but that’s probably because it seems more familiar. It’s certainly what I would try to do if I didn’t have the advantage of Walsh’s and tusharhero’s wisdom.

As I said, I never deal with SVG images so there may be better ways of handling all this but here, at least, are two solutions in case you are having the same problem.

-1:-- Rendering SVG Images In Org Generated HTML (Post Irreal)--L0--C0--2025-10-21T14:58:15.000Z

Jiewawa: Trying to do the last 20%

For the last few years, I have been using Emacs for almost all of my daily computing needs. In that time, I have also become fairly proficient at elisp. Across many files in my user-emacs-directory, I have hundreds of functions and snippets of code that I have written myself.

However, one area that I would like to improve is what I am calling “the last 20%”. These functions mostly work for me, but if I ever wanted to share these functions with others, then there is a lot of work that needs doing to get them into a ready state.

I previously wrote one set of code that could be packaged into a minor-mode and it was really rewarding when I once someone else using that code in their configuration.

Going forward, I want to tidy up and organise many of the functions into their own small packages so that I can maintain them better for myself. Below I will list some of the packages for which I have already written most of the logic, and are simply missing “the last 20%”.

Org-workout

This is a tool for tracking, analysing, planning and plotting workout data which are stored in human readable org files. This project is already on Codeberg.

Koreader-import

A tool for converting highlights from Koreader and importing them into the emacs highlight manager of your choice such as org-remark or paw.

eww-filters

A follow on to my eww-rdrview integration. Filters for web pages based on the URL. I chose to modify the HTML before emacs converts it to SXML, so that theoretically filters could be shared with other text based browsers. It already mostly works with w3m-filters

meow-paren

Create a lispy-like experience with meow. Overwrite meow vars in normal mode instead of making a new mode. I went into this tool with the idea of packaging it, so the conventions are good, but some logic is still missing.

Chinese Helpers

I realised that the file containing all my functions regarding learning Chinese and using it in emacs was about 800 lines long. I think some of these can be removed now, but I think other users could get some use out of some parts.

Conclusion

Recently, I have found myself having a bit more free time and have been enjoying hacking on emacs lisp. One of the things that makes emacs so amazing is the community, and I now want to give something back and this post will hopefully keep me accountable.

-1:-- Trying to do the last 20% (Post Jiewawa)--L0--C0--2025-10-21T00:00:00.000Z

Marcin Borkowski: A class register in Org Mode

My 9-year-old son loves playing school. He’s got a whiteboard, Mom, Sister and Dad are his pupils and he teaches them various real or made-up things. At the beginning he checks attendance, using a long list of made-up pupils’ names. Some time ago he decided that he’d like to keep the attendance data in a digital form. Mom helped him make a MS Word document (I know, I know…), where he puts little minuses for absentees and pluses for the attendees.
-1:-- A class register in Org Mode (Post Marcin Borkowski)--L0--C0--2025-10-20T19:13:59.000Z

Irreal: World Clock Improved

In the old days, World Clocks were a sort of curiosity. There wasn’t a lot of need for them because most folks communicated with distant friends and colleagues with snail mail and later, I suppose, with email. In any event you didn’t need to know what time it was at the destination unless you were making an almost certainly hideously expensive phone call.

Now, of course, you can instantly message someone—or even call them in many circumstances—with no charge and it’s best to know that it’s not 3 AM where they are. That’s why, today, a world clock is almost a necessity. You can always ask the Duck or whatever you use but if you’re communicating with several people, it’s convenient to have your own world clock with all the appropriate times.

Emacs, as usual, has us covered. There’s the world-clock command that gives you the current time in a few cities but if you’re parochial like me, knowing what time it is in London doesn’t help much if I want to talk to someone in, say Glasgow. Maybe it’s the same time zone; maybe it isn’t. I have no idea. Like most things in Emacs, the cities displayed are configurable but it’d be pretty inconvenient to add cities on the fly.

The other problem is that only the current time is displayed. What if you’re trying to set up a meeting and want to know what time it will be sometime in the future? It would be nice to be able to adjust both the cities and the time displayed.

Álvaro Ramírez had these problems and being Ramírez he wrote a package that solves both of them. You can add cities on the fly and adjust the base time forward and backward. Right now, the package is only on GitHub so you have to get it from his GitHub repository but he’ll probably put it up on Melpa eventually.

This is a great package that makes figuring out what time it is/will be/was in some arbitrary place in the world easy. Take a look. It may be something you didn’t realize you needed.

-1:-- World Clock Improved (Post Irreal)--L0--C0--2025-10-20T15:32:16.000Z

Sacha Chua: 2025-10-20 Emacs news

: Fixed org-linkin link, thanks gnomon-!

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

View org source for this post

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

-1:-- 2025-10-20 Emacs news (Post Sacha Chua)--L0--C0--2025-10-20T14:54:58.000Z

tusharhero: SVG? Yes!

~165 words. ~0 minutes.

This post by nwalsh shows how to use SVG in Org generated HTML pages. I would like to showcase yet another way you can use SVGs in Org generated HTML pages, and that is through Org Babel.

( let ((svg (svg-create 400 400  :stroke-width 10)))
  (svg-gradient svg  "gradient1" 'linear '((0 .  "red") (100 .  "blue")))
  (svg-circle svg 200 200 100  :gradient  "gradient1"
               :stroke-color  "green")
  ( with-temp-buffer
    (svg-print svg)
    (buffer-substring-no-properties (point-min) (point-max))))

These are the header arguments I used,

#+begin_src emacs-lisp :exports both :results html

I have been wanting to do some dynamically generated SVG images on my website, but I haven't gotten many ideas yet.

I currently only use this technique (without the SVG) for generating those colorful random dots on the homepage.

-1:-- SVG? Yes! (Post tusharhero)--L0--C0--2025-10-20T04:00:00.000Z

Irreal: Emacs On The Go

It’s Sunday and nobody—especially me—feels like working so here’s a short interlude while we’re waiting for the new week to begin. The subject of today’s post falls in the broad category of what could be called “mobile Emacs”.

Most of us have wished for a way to take Emacs with us when we’re out and about. Certainly, no one would want to do any serious editing on a smart phone—although Po Lu has produced an Android port—but it’s not hard to imagine using it on an iPad or other powerful tablet.

Then there’s this guy who literally wears his computer complete with a heads up display so that he always has access to his Emacs. When I saw the video, I immediately thought of Neal Stephenson’s gargoyles from Snow Crash. It’s the exact same idea: people wearing computers—and looking odd—so they can stay continuously connected to the metaverse or what we in this world call “the net”.

As much as some of us would like to be permanently connected, I doubt that many of us are prepared to embrace the solution suggested in the video. Of course, I could be wrong and it’s just what people are looking for. Let us know what you think.

-1:-- Emacs On The Go (Post Irreal)--L0--C0--2025-10-19T14:49:20.000Z

Alvaro Ramirez: Emacs time-zones

Emacs ships with a perfectly functional world clock, available via M-x world-clock. Having said that, there are two things I wish it had:

  1. A quick way to interactively add any city (bonus points for fuzzy search).
  2. An easy way to shift the time back and forth.

As far as I can tell, these are neither available nor possible on the built-in world-clock (please correct me if otherwise), so when my friend across the world recently asked me for the best time to meet, I knew this was the last nudge I needed to get this done.

With that, I give you M-x time-zones (now on GitHub).

There isn't much to talk about other than time-zones accomplishes the above tasks very easily without resorting to writing elisp nor accessing via customize, which I seldom use.

As I mentioned, time-zones is on GitHub if you'd like to give it a spin. It's super fresh, so please report any issues. Hope you like it.

Make it all sustainable

Reckon time-zones will be useful to you? Enjoying this blog or my projects? I am an indie dev. Help make it sustainable by ✨sponsoring

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

-1:-- Emacs time-zones (Post Alvaro Ramirez)--L0--C0--2025-10-19T00:00:00.000Z

Irreal: How To Speed Up Emacs

Over at the Emacs subredit, iinnssdd says he was looking for a guide to speed up Emacs but couldn’t find one. Therefore, he put together his own. This is more than the usual “how to make Emacs load faster” article, which we all know are silly and a waste of time. Although there are some suggestions for making Emacs load faster, the useful parts are how to make Emacs run faster once it’s loaded.

Some of that are compile time options when building Emacs from source. Iinnssdd’s particular options may or may not apply to your situation but they’re worth taking a look at. Another obvious strategy is to make sure that you have native compilation enabled. Iinnssdd has some suggestions for that.

A couple of specific recommendations are applicable to many of us. They’re both pretty simple and easy to implement. The first is a hook function to the find-file function that looks at how many lines the function has and turns off display-lne-numbers-mode when there are more than 1000 lines. It’s easy to see why this would speed things up on large files.

The second speedup is similar. It’s another find-file hook that looks for C files that have more than 1000 lines and turns on simpc-mode when it finds one. Simpc performs minimal syntax highlighting and indentation and, according to its author, is much faster than c-mode, c++-mode, cc-mode, and so on.

Even though I don’t have native compilation enabled on my older MacBook (2019), I still don’t find Emacs insufferably slow. That could be one of the benefits of having grown up with much older computers that were really slow. Regardless, if you’re intent on squeezing every bit of performance from Emacs, Iinnssdd’s post may give you some ideas.

-1:-- How To Speed Up Emacs (Post Irreal)--L0--C0--2025-10-18T14:49:52.000Z

Protesilaos Stavrou: Emacs: Denote version 4.1.0

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

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

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

Below are the release notes.


Version 4.1.0 on 2025-10-17

The overarching theme of version 4.1.0 is that of continuing to deliver on the highly hackable/flexible/powerful potential of Denote. All the core functionality is the same as before and you still only need a tiny configuration to use Denote productively. We are adding more refinements and subtle improvements under the hood, while making it even easier for advanced users/developers to piece together a workflow that matches their particular needs.

Since version 4.0.0, we have moved the “Denote extras” files into their own packages. I cover their changes further down after I elaborate on all the changes to the core Denote package:

Note that I write all the release notes by hand. The reason is that I consider this process an essential part of my role as a maintainer. Taking the time to review and document everything ensures that (i) I am well informed about the state of the package, (ii) I did not forget anything about this development cycle, and (iii) I take another look at the changes we made to ensure everything is in order.

Overview of the new features for core Denote

  • The user option denote-directory can be assigned to a list of directories. The original string value is also acceptable and remains the default.

  • Advanced users can define a completely custom scheme for identifiers. This can be as simple as automatically assigned ordinal numbers to increasingly complex patterns that may also involve user input.

  • The command denote-find-backlink-with-location is like denote-find-backlink except it also moves to the exact location of the link in the corresponding file.

  • All Denote buffer names share a common prefix, which is subject to the user option denote-buffer-name-prefix. This makes it easier to spot them in the buffer list.

  • The command denote-dired (alias denote-sort-dired) can sort files by random and last-modified in addition to the methods that involve Denote file name components.

  • The user option denote-query-sorting controls how files in all query buffers are sorted by default. This covers backlinks, query links for file contents, and any buffer produced by the denote-grep command. It benefits from the internal “Denote sort” mechanism, which is also used by denote-dired and the Org dynamic blocks of the denote-org package.

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

Set denote-directory to a list of directories

The user option denote-directory can optionally be bound to a list of file system paths, each of which represents a directory root, such as '("/home/prot/Documents/work/" "=/home/prot/Git/hut/") (Denote has always supported subdirectories, even for a singular denote-directory).

When creating new files, such as with the denote command, the first directory on the list will be selected. This can be changed by modifying the denote-prompts user option so that it asks for a directory or subdirectory thereof. Or by writing small wrapper commands that put files in a predefined directory, like this:

(defun my-denote-for-work ()
  "Like `denote' but always use the ~/Documents/work/ directory."
  (interactive)
  (let ((denote-use-directory "~/Documents/work/"))
    (call-interactively 'denote)))

Why have many directories as part of the denote-directory? Some users want to maintain separate directories with Denote files, while retaining the option of establishing links between (unlike the concept of “silos” we support, where the directories are self-contained). Those two directories can be their own Git repositories, for example, and have different syncing policies for access across multiple devices.

Thanks to Jean-Philippe Gagné Guay for providing the core functionality in pull request 609: https://github.com/protesilaos/denote/pull/609.

Jean-Philippe is a long-time contributor who has assigned copyright to the Free Software Foundation. I made several changes on top, such as to allow denote-dired (alias denote-sort-dired) to work with many directories, by finding their common root (which would ultimately be /).

Define completely custom Denote identifiers

The default Denote identifier should work for most people in most cases. I have considered the Denote file-naming scheme carefully and know it is reliable. Advanced users who have a clear use-case of something out-of-the-ordinary can now get “Denoted” file names with arbitrary identifiers. Since this is an advanced feature, I will not elaborate here on the technicalities. Though I have taken the time to write at length in the manual about it, with concrete examples ranging from simple to more complex scenaria. Start with this introduction: https://protesilaos.com/emacs/denote#h:3048f558-7d84-45d6-9ef2-53055483e801.

This feature has been discussed and requested for a long time, across several related issues:

Thanks, in no particular order, to mentalisttraceur, juh2, Christian Tietze, and Jean-Philippe Gagné Guay for sharing their thoughts. Also thanks to Jean-Philippe Gagné Guay for contributing the patches that made this possible, the last of which is in pull request 586: https://github.com/protesilaos/denote/issues/586.

Find a backlink at its exact location in the file

Denote has two ways of working with backlinks: (i) to display them in a dedicated buffer and (ii) to use a minibuffer prompt that supports completion in order to pick one file out of the list. The new command denote-find-backlink-with-location is of the latter kind. Like its more generic denote-find-backlink counterpart, it uses the minibuffer to pick a file that links to the current one. Then, it also moves the cursor to where the link is.

I did this is in response to issue 471 as reported by johkneisl: https://github.com/protesilaos/denote/issues/471.

Denote buffer names use the denote-buffer-name-prefix

This is a new user option that takes an arbitrary string. Its value is "[D]" by default. It consolidates how we name all of our buffers. Out-of-the-box, this applies to special buffers, like those produced by the commands denote-backlinks and denote-dired. When the optional minor mode denote-rename-buffer-mode is enabled, all buffers whose file naming scheme is that of Denote will get the denote-buffer-name-prefix in addition to their own denote-rename-buffer-format.

This is related to pull request 597 by James Kalyan: https://github.com/protesilaos/denote/pull/597. James has assigned copyright to the Free Software Foundation.

The Denote sort mechanism can sort by random and last-modified

In core Denote, this is used internally by the denote-dired command (alias denote-sort-dired) and the query buffers (more in the next section). By default, denote-dired prompts for the sort method and whether to reverse the order. Though there are user options to tweak its behaviour (consult the manual). The Org dynamic blocks of the denote-org package also rely on this mechanism (denote-org version 0.2.0).

Control the default sort of files in query buffers

Query buffers are those of denote-backlinks, denote-grep, and denote-query-contents-link (in the latter case, the query buffer is produced when you click on the link). Users can now modify how they sort matching files via the option denote-query-sorting. The sorting methods are by any of the Denote file names components (per denote-sort-components), random order, last modified, or an arbitrary function.

Thanks to Lucas Quintana for the contribution in pull request 594: https://github.com/protesilaos/denote/pull/594. Lucas has assigned copyright to the Free Software Foundation.

Miscellaneous for core Denote

  • The denote-dired command (alias denote-sort-dired) sets up its revert-buffer-function in a more robust way, such that it does not affect the window layout under certain conditions.

  • Fixed a bug with the menu entry of Denote that broke context-menu-mode. It addresses issue 592, as reported by artelse: https://github.com/protesilaos/denote/issues/592. Thanks to Lucas Quintana for the patch. Lucas has assigned copyright to the Free Software Foundation.

  • Thanks to ryota for refining the documentation of the variable denote-use-template and its potential interference with denote-org-capture-identifiers in custom user code. We discussed this in issue 545 and the patch was sent as pull request 598:
  • An internal check to determine if a file has backlinks is now faster than before: it exits with a non-nil value as soon as it finds one match, instead of trying to collect all the backlinks. Thanks to Yann Dutrieux for addressing an omission of mine in the original implementation and then for discussing with me some further refinements. Yann’s contribution was sent as pull request 637: https://github.com/protesilaos/denote/pull/637.

  • Thanks to Alan Schmitt and Ashish Panigrahi for fixing a couple of typos, in pull requests 623 and 626, respectively:

Git commits for core Denote

~/Git/Projects/denote $ git shortlog 4.0.0..4.1.0  --summary --numbered
   156	Protesilaos Stavrou
    29	Jean-Philippe Gagné Guay
     4	Lucas Quintana
     2	James Kalyan
     1	Alan Schmitt
     1	Ashish Panigrahi
     1	Hanwen Guo
     1	Ryota
     1	Yann Dutrieux

Changes to the extensions of Denote I maintain

This concerns all the former “Denote extras” that were shipped with core Denote as well as consult-denote.

consult-denote version 0.4.0

  • The commands consult-denote-grep and consult-denote-find also work when denote-directory is set to a list value, as explained further above (Set denote-directory to a list of directories).

  • There is a Consult-powered counterpart to the denote-sequence-file-prompt. It is for users of the denote-sequence package and comes into effect when the consult-denote-mode is enabled (that mode “Consults” all relevant minibuffer prompts Denote uses so they get the familiar preview functionality). The denote-sequence-file-prompt is used by commands such as denote-sequence, denote-sequence-find, and denote-sequence-link, among others (denote-sequence version 0.2.0).

  • The command consult-denote-find sorts its files by default. We discussed this with Gianluca Della Vedova and Gianluca implemented the tweak in pull request 18: https://github.com/protesilaos/consult-denote/pull/18. The change is small, meaning that Gianluca does not need to assign copyright to the Free Software Foundation.

denote-journal version 0.2.0

  • It is now possible to specify the desired interval used by the command denote-journal-new-or-existing-entry to determine what “new” and “existing” mean. Users may want to, for example, maintain one file per month, with daily entries as headings or as free-form text. The user option denote-journal-interval specifies the interval as a symbol among daily, weekly, monthly, and yearly. Thanks to Ning Xu for floating the idea of non-daily journaling in issue 18: https://github.com/protesilaos/denote-journal/issues/18.
  • The new user option denote-journal-signature specifies a signature that will be applied to all new journal entries. It is the counterpart of denote-journal-keyword. Possible values are nil, for no predefined signature, a string for a constant signature, and a function that returns a string which is then used as-is. Thanks to Halogen3576 for suggesting an option for a signature in issue 13: https://github.com/protesilaos/denote-journal/issues/13.

    In the case of a function value, users may wish to integrate the denote-journal package with the denote-sequence package (denote-sequence version 0.2.0). For example, each new journal entry should be defined as a new parent sequence. Thus:

    (setq denote-journal-signature
          (lambda ()
            (denote-sequence-get-new 'parent)))
    
  • The user option denote-journal-keyword is extended to support a function value which should return a string or list of strings.

  • The integration with M-x calendar (when the minor mode denote-journal-calendar-mode is enabled) is more robust when highlighting dates that have a Denote journal entry. Thanks to Alan Schmitt for the patch that improves the check for visible dates only. This was done in pull request 12: https://github.com/protesilaos/denote-journal/pull/12.

  • The denote-journal-calendar face is extended to also work when Emacs is ran in a TTY. Thanks to Ettore Berardi for the original contribution and for discussing this with me. It was done in pull request 14: https://github.com/protesilaos/denote-journal/pull/14. The contribution is less than 15 lines of code, meaning that Ettore does not need to assign copyright to the Free Software Foundation.

  • The function denote-journal-path-to-new-or-existing-entry is tweaked to not kill the buffer of the new file it might generate. Thanks to jbwfu for the change in pull request 17: https://github.com/protesilaos/denote-journal/pull/17. The change is small, meaning that the author does not need to assign copyright to the Free Software Foundation.

  • Dates with a single digit in the title of a new journal entry no longer have a space where the second digit normally is. So something like October 1 instead of October 1. Thanks to Josh Kingsley for the patch. The change is small, meaning that Josh does not need to assign copyright to the Free Software Foundation. It was done in pull request 24: https://github.com/protesilaos/denote-journal/pull/24.

  • Thanks to gk2803 for renaming a couple of old symbols to their current names in the commentary of the package. This was done in pull request 10: https://github.com/protesilaos/denote-journal/pull/10.

    ~/Git/Projects/denote-journal $ git shortlog 0.1.0..0.2.0  --summary --numbered
        35	Protesilaos Stavrou
         3	Alan Schmitt
         2	Ettore Berardi
         1	Abdelhak Bougouffa
         1	Josh Kingsley
         1	gk2803
         1	jbwfu
    

denote-org version 0.2.0

  • A new Org dynamic block integrates with the denote-sequence package (denote-sequence version 0.2.0). The block is called denote-sequence and can be inserted at point with the command denote-org-dblock-insert-sequence. What this block does is list the descendants of a given sequence up to a maximum depth. The presentation is a typographic list of lists to visualise the hierarchy of the complete sequence, with each set of children nested under its parent. Thanks to Peter Prevos for the original implementation in pull request 9 and for subsequent tweaks in pull request 13. Other changes by me are done to ensure tighter integration with the denote-sequence package.
  • All Org dynamic blocks that have a :sort-by-component parameter can now sort by random and last-modified. This is made possible by the aforementioned improvements to the core Denote sort mechanism (The Denote sort mechanism can sort by random and last-modified).

  • The denote-missing-links Org dynamic block, which can be inserted at point with the command denote-org-dblock-insert-missing-links takes an optional :not-regexp parameter. This is a regular expression of files to omit from the results. Same for the denote-backlinks block, which can be inserted at point with the command denote-org-dblock-insert-backlinks.

  • The denote-files-as-headings Org dynamic block, which can be inserted at point with the command denote-org-dblock-insert-files-as-headings now also accepts an optional :exclude-tags parameter. It is either nil or non-nil and determines whether the heading will have the file’s #+filetags as its own tags. Thanks to Matt Nolan for suggesting this idea in issue 14: https://github.com/protesilaos/denote-org/issues/14.

    ~/Git/Projects/denote-org $ git shortlog 0.1.0..0.2.0  --summary --numbered
        42	Protesilaos Stavrou
         8	Peter Prevos
    

denote-sequence version 0.2.0

  • The new commands denote-sequence-find-next-sibling and denote-sequence-find-previous-sibling move to the next or previous sibling in the given sequence. When called interactively, they work relative to the current file. When called from Lisp, they expect a SEQUENCE argument and its corresponding RELATIVES.

  • The denote-sequence-dired command is updated to (i) work with a list value for denote-directory (Set denote-directory to a list of directories), as noted further above and (ii) benefit from the refinements done to denote-dired with regard to its revert-buffer-function.

  • The new command denote-sequence-rename-as-parent makes it easier to apply the Denote file-naming scheme to an existing file and make it a new parent sequence. Thanks to Alex Carney for requesting something along those lines in issue 4: https://github.com/protesilaos/denote-sequence/issues/4.

    [ Remember that Denote is highly adaptable/hackable, meaning that many of these convenience commands build on top of the core with small extensions to it. The body of denote-sequence-rename-as-parent is only 4 lines long, two of which are for an error check. This is typical of much of what we provide and is how users can always extend Denote to do something slightly different than what we support out-of-the-box. ]

  • Made several other refinements under the hood, including the addition of more tests. In this regard, thanks to Rory Molinari, Peter Prevos, and Ashton Wiersdorf for fixing three bugs in pull requests 5, 8, and 11, respectively:

    ~/Git/Projects/denote-sequence $ git shortlog 0.1.0..0.2.0  --summary --numbered
        61	Protesilaos Stavrou
         1	Ashton Wiersdorf
         1	Peter Prevos
         1	Rory Molinari
    

Changes to denote-markdown

Nothing of substance.

Changes to denote-silo

Nothing of substance.

-1:-- Emacs: Denote version 4.1.0 (Post Protesilaos Stavrou)--L0--C0--2025-10-17T00:00:00.000Z

Irreal: Bending Emacs 3: Git Clone

One of the nice things about Emacs is that when you find yourself performing the same set of steps repeatedly, it’s easy to capture those steps into an Emacs function or even a keyboard macro. If you’re like me, you’ll keep repeating those steps over and over until one day you realize that you really should automate them. Álvaro Ramírez has a video showing a nice example of this: cloning a git repository.

Ramírez begins his video by showing his old procedure. It’s really simple. Capture the URL to the clipboard, change into the target directory, paste the URL into a git clone command on the Eshell command line, execute it, and open the directory in Dired. If there’s a README, open it as the last step. It takes longer to write it down than it does to actually do it.

Still, they’re simple steps and easy to automate, which is what Ramírez did. His solution is nice. He just has to capture the URL and call his function. Everything else, including opening the README file is handled automatically. He has a bit of code to allow choosing the target directory if he doesn’t want to use the current directory. You can check out his code in his GitHub repository. It is, as I say, simple but it’s a nice example of removing friction from your workflow: just let Emacs handle the routine chores.

The video is only 6 minutes, 54 seconds long so you should have no problem finding time for it. It’s interesting and worth a few minutes of your time.

-1:-- Bending Emacs 3: Git Clone (Post Irreal)--L0--C0--2025-10-16T15:01:31.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!