Alvaro Ramirez: A richer Journelly org capture template

16 May 2025 A richer Journelly org capture template

In addition to including user content, Journelly entries typically bundle a few extra details like timestamp, location, and weather information, which look a little something like this:

rice-guys.jpg

Behind the scenes, Journelly entries follow a fairly simple org structure:

* [2025-04-23 Wed 13:24] @ Waterside House
:PROPERTIES:
:LATITUDE: 51.518714352892665
:LONGITUDE: -0.17575820941499262
:WEATHER_TEMPERATURE: 11.4°C
:WEATHER_CONDITION: Mostly Cloudy
:WEATHER_SYMBOL: cloud
:END:
Try out Rice Guys #food #london on Wednesdays in Paddington

[[file:Journelly.org.assets/images/C5890C25-5575-4F52-80D9-CE0087E9986C.jpg]]

While out and capturing entries from my iPhone, I rely on Journelly to leverages iOS location and weather APIs to include relevant information. On the other hand, when capturing from my Macbook, I rely on a basic Emacs org capture template (very similar to Jack Baty's):

(setq org-capture-templates
      '(("j"  "Journelly" entry (file  "path/to/Journelly.org")
          "* %U @ Home\n%?"  :prepend t)))

These templates yield straightforward entries like:

* [2025-05-16 Fri 12:42] @ Home
A simple entry from my Macbook.

I've been using this capture template for some time. It does a fine job, though you'd notice location and weather info aren't captured. No biggie, since the location of my laptop isn't typically relevant, but hey today seemed like a perfect day to get nerd snipped by @natharari.

And so, off I went, to look for a utility to capture location from the command line. I found CoreLocationCLI, which leverages the equivalent macOS location APIs. As a bonus, the project seemed active (modified only a few days ago).

Installing CoreLocationCLI via Homebrew was a breeze:

brew install corelocationcli

The first time you run corelocationcli, you'll get an message like:

"CoreLocationCLI" can't be opened because it is from an unidentified developer...

You'll need to follow CoreLocationCLI's instructions:

To approve the process and allow CoreLocationCLI to run, go to System Settings ➡️ Privacy & Security ➡️ General, and look in the bottom right corner for a button to click.

After approving the process, I ran into a snag:

$ CoreLocationCLI
CoreLocationCLI: ❌ The operation couldn’t be completed. (kCLErrorDomain error 0.)

Lucky for me, the README had the solution:

Note for Mac users: make sure Wi-Fi is turned on. Otherwise you will see kCLErrorDomain error 0.

Oddly, my WiFi was turned on, so I went ahead and toggled it. Success:

$ CoreLocationCLI
51.51871 -0.17575

We can start by wrapping this command-line utility return coordinates along with reverse geolocation (ie. description):

(defun  journelly-get-location ()
   "Get current location.

 Return in the form:

 `((lat . 51.51871)
   (lon . -0.17575)
   (description . \"Sunny House\"))

 Signals an error if the location cannot be retrieved."
  (unless (executable-find  "CoreLocationCLI")
    (error  "Needs CoreLocationCLI (try brew install corelocationcli)"))
  (with-temp-buffer
    (if-let ((exit-code (call-process  "CoreLocationCLI" nil t nil
                                       "--format"  "%latitude\t%longitude\t%thoroughfare"))
             (success (eq exit-code 0))
             (parts (split-string (buffer-string)  "\t")))
        `((lat . ,(string-to-number (nth 0 parts)))
          (lon . ,(string-to-number (nth 1 parts)))
          (description . ,(string-trim (nth 2 parts))))
      (error  "No location available"))))

Now that we're able to get the current location, we need a way to fetch weather info. I discarded using WeatherKit on macOS, since it requires setting up a developer account and obtaining an API key. No worries, I found the great MET Norway API which is freely available without the need for keys.

(defun  journelly-fetch-weather (lat lon)
   "Fetch weather data from MET Norway API for LAT and LON.

 Return the parsed JSON object."
  (let* ((url (format  "https://api.met.no/weatherapi/locationforecast/2.0/compact?lat=%s&lon=%s" lat lon))
         (args (list  "-s" url)))
    (with-temp-buffer
      (apply #'call-process  "curl" nil t nil args)
      (goto-char (point-min))
      (json-parse-buffer  :object-type 'alist))))

We can take it for a spin with:

(journelly-fetch-weather 51.51871 -0.17575)

We get a nice object with a chunky time series (cropped for readability):

((type .  "Feature")
 (geometry (type .  "Point") (coordinates . [-0.1758 51.5187 30]))
 (properties
  (meta (updated_at .  "2025-05-16T11:17:44Z")
        (units (air_pressure_at_sea_level .  "hPa")
               (air_temperature .  "celsius")
               (cloud_area_fraction .  "%")
               (precipitation_amount .  "mm") (relative_humidity .  "%")
               (wind_from_direction .  "degrees") (wind_speed .  "m/s")))
  (timeseries
   . [((time .  "2025-05-16T12:00:00Z")
       (data
        (instant
         (details (air_pressure_at_sea_level . 1025.6)
                  (air_temperature . 18.0) (cloud_area_fraction . 4.7)
                  (relative_humidity . 44.2)
                  (wind_from_direction . 17.6) (wind_speed . 3.6)))
        (next_12_hours (summary (symbol_code .  "fair_day")) (details))
        (next_1_hours (summary (symbol_code .  "clearsky_day"))
                      (details (precipitation_amount . 0.0)))
        (next_6_hours (summary (symbol_code .  "clearsky_day"))
                      (details (precipitation_amount . 0.0)))))

      ...


     ((time .  "2025-05-26T00:00:00Z")
       (data
        (instant
         (details (air_pressure_at_sea_level . 1007.3)
                  (air_temperature . 12.6)
                  (cloud_area_fraction . 28.1)
                  (relative_humidity . 91.3)
                  (wind_from_direction . 258.7) (wind_speed . 3.5)))))])))

Journelly entries need only a tiny subset of the returned object, so let's add a helper to extract and format as preferred.

(defun  journelly-fetch-weather-summary (lat lon)
   "Fetch weather data from MET Norway API for LAT and LON.

 Return in the form:

  '((temperature . \"16.9°C\")
    (symbol . \"cloudy\"))."
  (let* ((data (journelly-fetch-weather lat lon))
         (now (current-time))
         (entry (seq-find
                 (lambda (entry)
                   (let-alist entry
                     (time-less-p now (date-to-time .time))))
                 (let-alist data
                   .properties.timeseries)))
         (unit (let-alist data
                 .properties.meta.units.air_temperature)))
    (unless entry
      (error  "Couldn't fetch weather data"))
    (let-alist entry
      `((temperature . ,(format  "%.1f%s"
                                .data.instant.details.air_temperature
                                (cond
                                 ((string= unit  "celsius")  "°C")
                                 ((string= unit  "fahrenheit")  "°F")
                                 (t (concat  " " unit)))))
        (symbol . ,(alist-get 'symbol_code .data.next_1_hours.summary))))))

We can take it for a spin with:

(journelly-fetch-weather-summary 51.51871 -0.17575)

Nice! Look at that, it's a sign that I should finish writing and go outside!

'((temperature .  "19.0°C")
  (symbol .  "clearsky_day"))

I really should go outside, I'm just so close now… Or so I thought! That symbols (ie. "clearsky_day") isn't recognizable by Journelly, which relies on SF Symbols returned by WeatherKit. I need some sort of mapping between these symbols. Gosh, I need to go outside and this is a perfect task for a robot! Whipped out chatgpt-shell and asked the LLM robots to take on this grunt work, who gave me:

{
   "clearsky_day":  "sun.max",
   "clearsky_night":  "moon.stars",
   "clearsky_polartwilight":  "sun.horizon",
  ...
   "snowshowers_and_thunder_day":  "cloud.sun.bolt.snow",
   "snowshowers_and_thunder_night":  "cloud.moon.bolt.snow",
   "thunderstorm":  "cloud.bolt"
}

We're in elisp land so who wants json? Hey robot, I need an alist:

chatgpt-shell.png

Won't the LLM make mapping errors? Most certainly! But for now, I'm just getting a rough prototype and I need to get moving if I want to go outside!

We plug our mapping into an elisp function

(defun  journelly-resolve-metno-to-sf-symbol (symbol)
   "Resolve Met.no weather SYMBOL strings to a corresponding SF Symbols."
  (let ((symbols '(("clearsky_day" .  "sun.max")
                   ("clearsky_night" .  "moon.stars")
                   ("clearsky_polartwilight" .  "sun.horizon")
                   ...
                   ("snowshowers_and_thunder_day" .  "cloud.sun.bolt.snow")
                   ("snowshowers_and_thunder_night" .  "cloud.moon.bolt.snow")
                   ("thunderstorm" .  "cloud.bolt"))))
    (map-elt symbols symbol)))

Does it work? Kinda seems like it.

(journelly-resolve-metno-to-sf-symbol
 (map-elt (journelly-fetch-weather-summary 51.51871 -0.17575) 'symbol))
 "sun.max"

We got everything we need now, let's put the bits together:

(defun  journelly-generate-metadata ()
  (let* ((location (journelly-get-location))
         (weather (journelly-fetch-weather-summary
                   (map-elt location 'lat)
                   (map-elt location 'lon))))
    (format  "%s
 :PROPERTIES:
 :LATITUDE: %s
 :LONGITUDE: %s
 :WEATHER_TEMPERATURE: %s
 :WEATHER_SYMBOL: %s
 :END:"
            (or (map-elt location 'description)  "-")
            (map-elt location 'lat)
            (map-elt location 'lon)
            (alist-get 'temperature weather)
            (journelly-resolve-metno-to-sf-symbol
             (alist-get 'symbol weather)))))

Lovely, we now get the metadata we need.

Waterside House
 :PROPERTIES:
 :LATITUDE: 51.51871
 :LONGITUDE: -0.175758
 :WEATHER_TEMPERATURE: 18.5°C
 :WEATHER_SYMBOL: sun.max
 :END:

Damn, the temperature is dropping. I really do need to go outside. So close now!

All we have to do is plug our journelly-generate-metadata function into our org template and… Bob's your uncle!

(setq org-capture-templates
      '(("j"  "Journelly" entry (file  "path/to/Journelly.org")
          "* %U @ %(journelly-generate-metadata)\n%?"  :prepend t)))

We can now invoke our trusty M-x org-capture and off we go…

capture.gif

journelly.jpeg

While the code currently lives in my Emacs config, it's available on GitHub. If you do take it for a spin, it may crash and burn. I blame the weather. In the UK, when sunny, you rush to go outside! 🌞🏃‍♂️💨

-1:-- A richer Journelly org capture template (Post Alvaro Ramirez)--L0--C0--2025-05-16T14:30:37.000Z

The Emacs Cat: Windows Navigation in Emacs

Last week there were some quite interesting posts about windows management in Emacs — Emacs’ windows navigations and some Emacs zen (a review by Irreal), Emacs window management tweaking, for instance.

In this regard, I’ve decided to share my configuration for the issue.

For switching between windows in Emacs I use the ace-window package by Oleh Krehel aka abo-abo, a renowned author of such gems as Hydra, avy, Swiper, and others. Most of these packages have found their place in my .emacs.

My configuration is quite simple.

(use-package avy :ensure t)
(use-package ace-window :ensure t
  :after avy
)

(global-set-key [(f2)]  #'ace-window)

The main function, ace-window is meant to replace other-window by assigning each window a short, unique label. When there are only two windows present, other-window is called… If there are more, each window will have its first label character highlighted. Once a unique label is typed, ace-window will switch to that window.

By default, ace-window uses numbers for window labels so the window labeling is intuitively ordered.

I’ve bound ace-window to <F2>. Why <F2>? For ergonomic reasons. On most keyboards, the numeric keys (1-2-3-…) are located right under the <F2> key. It would be easy to press <F2> then, for example, 2 using the same finger.

Window labels are in the top left corner of each window (shown in red). The frame is dimmed when activating `ace-window`.

The ace-window package has many other options; you can find more detailed information at the ace-window GitHub repository.

Happy emacsing!

— The Emacs Cat.

-1:-- Windows Navigation in Emacs (Post The Emacs Cat)--L0--C0--2025-05-16T09:11:27.000Z

Irreal: A Garbage Collection Strategy

One of the strengths—or weaknesses, depending on your point of view—of Lisp is garbage collection. That means that memory no longer in use is automatically collected and made available to the system without depending on the programmer to release it the way we do in, say, C. Of course, that comes at a cost. Garbage collection can block other operations while it’s running. That’s especially true in the single threaded Emacs.

One often sees complaints about this in the various forums. There’s all sort of advice about what to do. Some say you should set the garbage collection threshold (the amount of collectible memory) high so that garbage collection isn’t triggered as often. Of course, that means that it takes longer to collect the unused memory.

Another suggestion is to set the threshold low so that unused memory can be collected quickly. That means, though, that garbage collection is run more often. Depending on your workflow, either—or possibly both—of these strategies may work well for you.

There’s a third, arguably better, strategy: only garbage collect when the system is idle. That’s facile advice, of course, because it begs the question of how you know when the system is idle. There’s a useful heuristic. If the system has been idle for x seconds it will probably continue being idle long enough for a garbage collection cycle. The question then boils down to the proper value for x.

Jack Jamison believes x should be small and uses 1.2 seconds in his implementation of this strategy. He says that he’s had excellent results with that value. The older GCMH system uses 15 seconds.

I’ve been using GCMH was several years and can’t remember having any garbage collection issues since I started. GCHH lets you configure the idle time but the 15 second setting has been working well for me so I’m not inclined to mess with it.

In any event, if your Emacs is experiencing garbage collection delays it’s worth trying this strategy. If you want a simple prepackaged solution, GCMH is for you. If you want to keep everything in your init.el and avoid external packages, take a look at Jamison’s post to get started.

-1:-- A Garbage Collection Strategy (Post Irreal)--L0--C0--2025-05-15T15:43:32.000Z

Two Eamcs tweaks I forgot about (most of you will know these):

Use Consult’s recentf to see a list of files that were edited recently:

  (global-set-key (kbd "C-x C-r") 'consult-recent-file)

Consult’s org-agenda (jump to heading) is quicker than what I usually do, which is to list all ACTIVE keywords in emacs (this is how I list my projects), and then go down the tree to find the specific TODO header I want.

Since I often know what I’m looking for within active projects, I can use consult-org-agenda, which narrows headers dynamically as I search. Much faster and clutter-free:

  (global-set-key (kbd "C-c C-h") 'consult-org-agenda)
-1:--  (Post TAONAW - Emacs and Org Mode)--L0--C0--2025-05-15T14:16:02.000Z

Irreal: Unsetting Keybindings

Back before I became an Emacser, a friend who was an Emacser said that I shouldn’t worry about the Emacs keybindings because I could configure them to be whatever I want. I remember thinking that that would be disaster. After all, what would I do if I were using Emacs on someone else’s computer or even setting up a new computer.

Now, of course, I have a very individualistic configuration that makes working on someone else’s computer uncomfortable. Uncomfortable but not impossible. That’s because although I have all sorts of specialized editing commands, I’ve left the “vanilla” editing commands—cursor movements, file visiting and saving, and other standard operations—alone. That means that if I use someone else’s Emacs I can edit successfully, if not optimally, as long as the guest Emacs also didn’t mess with the standard bindings.

That’s why I’m not entirely sympathetic to The MKat’s post on how to unset default key bindings. She’s got a lot of great advice on how to delete keybindings and I agree that it’s useful information to have. My objection is to the notion that you should delete bindings that you don’t like.

Just yesterday, I discussed how modern keyboards aren’t optmal for Emacs so it’s natural to want to fix that somehow. Yesterday’s post suggests some ways of doing that but none of them involve changing default keybindings.

Sure, some folks have special needs that make one binding or another difficult but in general, I think it’s a bad idea to be messing with them. Of course, this is Emacs and everyone can adjust it to their liking. I’m not arguing with that. I’m only saying that if you stay with the defaults it will be easier for you to use an alien Emacs.

-1:-- Unsetting Keybindings (Post Irreal)--L0--C0--2025-05-14T16:33:44.000Z

Irreal: The Best Emacs Keyboards

Over at the Emacs subreddit, surveypoodle asks a perennial question: what are the best keyboards for Emacs? He points out that Emacs pinky seems to have appeared rather late in the editor’s history and speculates that that’s because the keyboards originally used with Emacs were better suited for it than modern keyboards that make many of the bindings awkward. He’s asking what modern keyboards are best for dealing with RSI.

If you’re interested in an answer to the question, see the comments to surveypoodle’s post. There are all sorts of suggestions. Reading through them, I realized that I didn’t care.

I used to yearn for a reincarnation of the Space Cadet keyboard—okay, I still have some vestigial urges—but I realized that these days I do virtually all my work on my laptop. I’m guessing the same is true many of us. Regardless, the use of a laptop pretty much makes the choice of a keyboard for you. Sure, you can use a third party keyboard but unless you’re always working at (the same) desk it’s just too much trouble. As I’ve said before, I do a lot of my work on the couch so an external keyboard isn’t a practical choice for me.

What to do? As much as it has become a cliche, Emacs pinky—or more generally Emacs induced RSI—is a real thing.The best solution I’ve found is some simple keyboard modifications. I’m using a MacBook Pro so keyboard firmware modifications aren’t an option. What I can do, though, is arrange for the modifier keys I use the most to be easy to reach. Two of those, Ctrl and Hyper are, configurable from within Emacs or macOS. The Meta key is bound to Alt by default so there’s nothing to do there. What all this means is that binding Ctrl to caps lock and Hyper to ⌘ Right Cmd, I can use my thumbs for Meta and Hyper and that Ctrl is an easy reach for my pinky.

I know that a lot of you are doing the same or similar things. If you’ve got a better solution, leave a comment.

-1:-- The Best Emacs Keyboards (Post Irreal)--L0--C0--2025-05-13T15:20:05.000Z

James Dyer: The Smallest of Productivity Gains by Instantly Opening Dired Files when isearching

If you’re an Emacs user (which I know you are), especially one who lives in dired-mode, you’re probably familiar with the quick power of isearch for finding files or directories. But if you’re like me, you might have noticed a tiny speed bump in the workflow: after finding a file or directory with isearch, you would typically have to hit <enter> to exit the search, and then <enter> again to open the entry. That’s two steps for something that feels like it should be one and this has been a very minor annoyance for me for a very long time now.

I had a little time to shave some more yak hair, so lets try and address this!

The solution I came up with was to add a bit of advice to isearch-exit, so now, when you’re in dired-mode and you use isearch to locate a file or directory, pressing <enter> will both exit the search and immediately open the file or directory, no need for a second confirmation.

Here’s the magic!

(defadvice isearch-exit (after dired-enter-directory-or-file activate)
  "In dired mode, enter directory or open file after isearch."
  (when (eq major-mode 'dired-mode)
    (let ((file (dired-get-file-for-visit)))
      (when file
        (dired-find-file)))))

The only thing I am a little worried about are the side effects, but I guess we shall see…

And another thing, now my dired navigation is one step smoother; how much time generally is it going to save me? Was it worth the effort?.

Let’s say, conservatively, that I have pressed that extra Enter 100 times each day. Each press takes, say, 150 ms, accounting for human reaction times, even though it isn’t really a reaction, more of a muscle memory response.

Let’s do the calculations! I have no idea why I’m doing this, but maybe I can validate the amount of time I spent on this for future time-saving gains. Maybe it will make me feel better about the countless hours of yak shaving I have done over many years (with Emacs, of course, although I do have a yak in the garden shed that really needs some attention!)

So, the savings are as follows:

  • Day: 15 seconds
  • Week: 105 seconds
  • Month: 7 minutes
  • Year: 1 hour 24 minutes

Well, the yearly total is probably about the amount of time I actually took to implement this, so that means in a year I will be making productivity gains! Sweeeeeeet!

-1:-- The Smallest of Productivity Gains by Instantly Opening Dired Files when isearching (Post James Dyer)--L0--C0--2025-05-13T08:20:00.000Z

Protesilaos Stavrou: Emacs: my new Doric themes

The doric-themes is my new in-development package for Emacs. It is a set of themes that conform with a minimalist aesthetic: they use few colours and appear monochromatic in many contexts. Below are the screen shots.

In terms of my overall theme work for Emacs, the doric-themes are the most minimalist, ef-themes the most maximalist, and the modus-themes remain what I consider the best “default theme” style. All of them are designed to be highly legible.

I plan to add doric-themes to GNU ELPA within the next days. For the time being, they are only available from source code: https://github.com/protesilaos/doric-themes.

Finally, the backronym for “Doric” is “Doric Only Really Intensifies Conservatively”.

Enjoy your new theme!

Samples

doric-light

doric-light theme sample

doric-marble

doric-marble theme sample

doric-earth

doric-earth theme sample

doric-wind

doric-wind theme sample

doric-dark

doric-dark theme sample

doric-obsidian

doric-obsidian theme sample

doric-fire

doric-fire theme sample

doric-water

doric-water theme sample

-1:-- Emacs: my new Doric themes (Post Protesilaos Stavrou)--L0--C0--2025-05-13T00:00:00.000Z

Marie K. Ekeberg: Emacs Quick Tip: Disable key bindings with global-unset-key

Do you also hate some of Emacs' default keybindings? Some of the default key bindings in Emacs don't really feel right for me, so I unset/remove them. Sometimes I override them with new operations. In this short article, I will show you how to yeet (remove) your unwanted keybindings.
-1:-- Emacs Quick Tip: Disable key bindings with global-unset-key (Post Marie K. Ekeberg)--L0--C0--2025-05-13T00:00:00.000Z

Sacha Chua: 2025-05-12 Emacs news

[2025-05-13 Tue]: Fixed link to The Emacs Widget toolkit. Thanks, MPL!

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-05-12 Emacs news (Post Sacha Chua)--L0--C0--2025-05-12T14:07:22.000Z

Marcin Borkowski: Coloring Git output in Magit

Today I have a very short and rather niche tip, but maybe someone will find it useful (as I did). Like many other people, I use Magit on a daily basis. One thing that bothered me a bit was the fact that when I pressed $ to see the output of the Git process, all colors were gone. This was a problem for me, since the pre-commit hook I use calls the TypeScript compiler to tell me about any potential problems with types in my code. By default, the output of tsc is colored with the ANSI color codes. While the coloring can be turned out, the setting to do that is rather crude (it also disables pretty-printing/formatting), and after all, these colors serve a purpose and are genuinely useful. I decided that before I turn the formatting off, it may be a good idea to check if Magit has an option to allow coloring the Git output using ANSI codes.
-1:-- Coloring Git output in Magit (Post Marcin Borkowski)--L0--C0--2025-05-12T06:23:14.000Z

Joar von Arndt: Web browsing in Emacs

Why would you want web browsing in a text editor?

Emacs has a tendency to try and absorb all user-facing interactions I have with a computer. Some people seem able to separate “Emacs stuff” — like programming or using org-mode for note taking — but Emacs’ extendability makes me want to use it for everything. For a long time I have only really needed four different tools to do any kind of work at a computer:

  1. GNU Emacs (with my personal config).
  2. Tailscale to connect to my other machines.
  3. Syncthing so that I have local access to my files1.
  4. A web browser (usually Firefox).

Quickly getting these four things up and running is usually my first priority when setting up a new machine, and they require different amounts of work. Critically Firefox requires a GUI environment in order to run, but it’s really quite unnecessary to get a desktop environment or tiling window manager up and running — and dealing with their conflicting keybinds — when all I’m going to be doing is working in Emacs perhaps 80% of the time, finding information or reading docs in Firefox 15% of the time, and using a stray terminal the remaining 5% (something I can easily replace with one of Emacs’ many terminal and shell solutions). This is why I like using exwm2. Rather than using Emacs’ window manager capabilities to manage all your X windows it allows you to stay continually within Emacs and just treat any stray non-Emacs GUI programs within the same system. The solution then seems to try and subsume web browsing into my preëxisting workflow. There are many solutions to this, but I prefer ones that work with text as the primary medium as that is what Emacs is best oriented to work with.

The Emacs Web Wowser (eww)

eww is probably the most well-known of Emacs’ web browsing solutions, chiefly because it comes included with it. It is also the one I have the most experience with. I first came across eww as a consequence of reading about all of the crazy features included in Emacs by default like Tetris and Gnus. This isn’t very surprising; web browsers are some of the largest ubiquitous user-facing applications, so the fact that Emacs ships with one as a tangential feature is very surprising. However, these visions of browsing the web are often quickly crushed when one uses eww for the first time. It does not load any CSS, so websites do not look like one is accustomed to, and a lot of javascript functionality is non-functional.

I expect this experience — or at least something like it — to be somewhat universal amongst those who have even tried using eww. The modern web is built around these technologies, and going without them might seem almost impossible. But there is a place for eww in a modern workflow. The strength of Emacs is its power for working with text, and most media I interact with in a web browser is text. Emacs then is really the perfect environment for this. Reading and rewriting the content of web pages side-by-side using the same key-chords and user-interface allows for minimal context friction. But there are serious downsides, primarily ugly formatted headers and images. Most of the time eww can figure out the main readable content using the eww-readable function, bound to R by default. It’s meant to strip out long “navigation menus and the like”. In my experience it is either hit or miss. For some web pages like wikipedia it seems to work well (but only for some pages), but for others like github it just strips out the entire page. Thankfully it is bound to a convenient key and its easy to switch between the two views quickly. Images are probably one of the first things that stops people from using eww, with large ones causing the site to jump around as they cover the whole screen and then disappear. I solved this using ultra-scroll, which provides scrolling smoother than you could ever imagine in Emacs. It also allows you to scroll intuitively over images, rendering them as you would expect in a traditional browser like Firefox. With a slow network connection eww can have some problems with blocking, but this can be remedied by setting eww-retrieve-command:

(setq eww-retrieve-command
      '("chromium" "--headless" "--dump-dom"))

eww is written by Lars Ingebrigtsen of gnus fame. It uses the shr (simple HTML Renderer) program written in elisp to render HTML. He originally wrote shr to read elfeed entries in Emacs and eww is merely the addition of browsing (or wowsing) capability built on top of it. shr’s elisp nature is why it can sometimes struggle with complicated site layouts, but in my experience it is usually fast enough, especially with native compilation.

Generally eww can be surprisingly powerful, but most of its power (like Emacs itself) comes from its tight integration with other tooling and extensibility with elisp, rather than any amazing workflow it has built for you in advance. There is very little to learn, but a lot to master.

w3m

w3m can some sense be seen as the “hardcore” version of text-based web browsing in Emacs. w3m relies on the eponymous TUI program to render web pages in a way similar to Lynx, allegedly the world’s oldest continually-maintained web browser. w3m even comes with lynx bindings by default, although you can also change them to the included “info-like” ones. It allows for tabs, bookmarks, and other features one would expect in a modern browser. It also relies on interpreting the raw HTML to format the page, rather than rendering CSS. Like eww it also does not support javascript. Like I alluded to earlier, this is both a blessing and a curse, and reading just straight text can be very nice, both from a therapeutic minimalist way and a way to minimize context-switching. It is also nice and async by default, since it uses an external binary to fetch websites, not that it takes very long to load to begin with since it’s not running any heavy javascript. One nice difference between w3m and eww is also that the arrow keys navigate to the next link in the page by default, and the text in the buffer will resize itself whenever the buffer is resized3, something that is very handy if you’re using a package like golden-ratio that resizes windows depending on focus.

Non-text based

While I prefer text-based browsers that fit more seamlessly into the rest of Emacs, there are other solutions for more traditional browser experiences.

Xwidgets

Since version 25 Emacs has had the ability to be compiled with xwidgets support, and to render complete web pages through webkit. To do this merely add the --with-xwidgets flag to Emacs when compiling, and then run M-x xwidget-webkit-browse-url to surf the web! Sadly this doesn’t work very well at the moment, as you’ll quickly realize if you were to do the above. There is apparently a bug in the xwidget library webkitgtk that causes Emacs to abort. Worse yet its status is wontfix since GNU Emacs seems to be the only program affected by it thanks to its old and strange ways of doing things. Upon crashing Emacs links to a 22 year old bug report that had its last message sent five years ago, so I’m not exactly holding out hope (but maybe a good project to work on for someone?). It seems to work with version 2.40 of webkitgtk so try and use that if you’re having issues. Sadly I have not gotten it to work but I keep seeing people mentioning xwidgets as an option so it might work on some machines.

EAF

Getting a non-text browser in the text-based environment of Emacs requires working around Emacs’ systems. EAF (Emacs Application Framework) does this through creating an exterior python system that then hooks into Emacs to run a number of programs, chief among them a webkit-based browser.

The largest problem I have with the EAF’s browser is not really with the browser itself, although it is a bit unstable, but instead with the EAF itself. Being part of this large group of packages that feel very external to Emacs they are troublesome to install and maintain as part of a workflow. Installing EAF (something you’re probably only doing for the browser) asks you individually if you’d like to install things like a git client, system monitor, file browser, terminal, multiple demos, and numerous other things. Some of these things are impressive and useful, but I’d rather explicitly say what I’d like to install instead of having a Y/N on each program. Imagine having to do that for every ELPA package when first launching Emacs! EAF is of course nowhere near that level, but it’s still a baffling design decision. It also makes it way less portable, since I can’t describe what EAF programs I want to install (although I can for which ones I want to use) in a declarative way. It also has a few issues with javascript that feel like deal-breakers for a graphical browser, I’d rather go all-the-way with a text-based browser like eww or use a fully functional graphical browser like firefox.

Footnotes:

1

I can use tailscale to edit the files remotely using TRAMP, but that is usually pretty slow since my home network is very unreliable. Much easier to just sync “asynchronously” when the network feels like it.

2

exwm has other issues, namely around multi-monitor setups. They make sense and are probably sacrifices I would have made had I created exwm, but I don’t really like working with frames instead of windows. It becomes another layer of friction, even if I’m still working within Emacs.

3

To try and replicate this behaviour in eww you have to run (eww-reload t), by default bound to C-u g, to refresh the buffer and reformat it. You can probably run it in a hook whenever you resize windows, but I don’t care to do that.

-1:-- Web browsing in Emacs (Post Joar von Arndt)--L0--C0--2025-05-11T22:00:00.000Z

Irreal: Window Placement When Using Dired

Courtesy of JTR from The Art Of Not Asking Why, here’s a handy tip for dealing with window placement when bringing up a Dired buffer. There are two problems.

The first doesn’t really concern window placement. Most often JTR wants to bring up a Dired buffer for whatever directory he’s already in. The easy way to do that is to use dired-jump (bound to Ctrl+x Ctrl+j) to open a buffer in the same directory as the current file.

The problem with that is that it opens the Dired buffer in the current window. JTR doesn’t want that. He wants to open Dired in some other window so that he can see his current file and the Dired buffer. The answer to that is simple: just ask Emacs to open Dired in another window. There’s a general protocol for doing that. Simply use Ctrl+x 4 Ctrl+J to call Dired. That will open Dired in the same directory as the current file but in another window.

The Ctrl+x 4 … works for a lot of commands. I use it to open files or buffers in another window several times a day. I used to consider it an esoteric maneuver but now I use it all the time. You can also open your windows in another frame by using 5 instead of 4.

The 4/5 protocol doesn’t work for all commands but it does for a lot of them. It’s a real time saver that I use repeatedly. It’s well worth internalizing.

-1:-- Window Placement When Using Dired (Post Irreal)--L0--C0--2025-05-11T15:35:39.000Z

Emacs APAC: Announcing Emacs Asia-Pacific (APAC) virtual meetup, Saturday, May 24, 2025

This month’s Emacs Asia-Pacific (APAC) virtual meetup is scheduled for Saturday, May 24, 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, May 24, 2025 (Post Emacs APAC)--L0--C0--2025-05-10T00:01:02.000Z

Irreal: Loading The Emacs Init File

Charles Choi makes an astute observation about the Emacs initialization file from the point of view of the new user: there’s no obvious way of loading it or even knowing that it exists. The problem is especially acute on the Mac where the File → Open menu uses the Mac file loading routines that don’t show dot files. Not very helpful even if you know the name of the file.

Choi is surprised that this far on the problem hasn’t been fixed. It’s hard to argue. On the other hand, I don’t remember having this problem. I have no memory at all of how I overcame it but I and thousands of others have. That doesn’t mean that the problem isn’t real, though.

Choi offers a solution. It’s a simple function that loads the init file even if it hasn’t been created yet. His idea is that the function would be builtin and automatically available to the new user.

Of course, the problem is how does the new user discover this function, or for that matter, what to do with the init file once it’s loaded. It seems to me that at the very least there needs to be some instructions on the startup screen—you know, that screen we all turn off as soon as we learn how. That would help but it’s probably not enough.

What’s really needed is a new-user file that explains how to get started. It could be linked from the startup screen. It wouldn’t need to be long or complicated; just enough to bootstrap the new users and point them to the tutorial.

One thing for sure: Choi is right. It’s really harder than it should be for a new user to learn enough to get up to speed with Emacs.

-1:-- Loading The Emacs Init File (Post Irreal)--L0--C0--2025-05-09T16:16:32.000Z

TAONAW - Emacs and Org Mode: Emacs' windows navigations and some Emacs zen

As I was looking more into widows management in Emacs, particularly viewing System Crafters' video about the topic which I mentioned in my previous post, I learned a couple of things (or maybe re-learned? I probably used to know about them at some point in the past).

One of my issues with windows in Emacs right now is that whenever I open Dired, it takes over my current window. I often just want to view my files in the directory my current buffer is in.

The answer is simple: instead of opening Dired (C-x d), just “jump” into Dired in another window, which is dired-jump-other-window or C-x 4 C-j. This improves my workflows twice: first, I usually want to open Dired in the directory the buffer I’m working in is, and second, I want it in another window. With this command, I don’t need to specify the directory; it just takes me where I want1.

Also, as I was writing this post, I realized another problem with Emacs windows placement was actually my problem all along (user error dance, anyone?): C-x b is bound to consult-buffer-other-window on my system, which does what it says, opening the buffer I want in the other window. I thought this was the command to open a buffer, forgetting that there’s such a thing as opening a buffer in the other window. Using the logic I just learned, it would probably make more sense to bind consult-buffer-other-window to C-x 4 b (for me, it runs the default Emacs switch-to-buffer-other-window, which I don’t use2) and then consult-buffer (which is not bound to anything for me) to be C-x b. This will disrupt my muscle memory for a while, but eventually it will lead to a better workflow.

Another nice thing I didn’t know and learned from watching this video is that I can scroll up and down in the other window while still keeping the focus on the current buffer with M-pgup and M-pgdn. This is nice if I want to read help documentation while working on something, reading definitions with Emacs' built-in dictionary, or maybe using Occur or something similar, where just reading for reference is enough.

Then we have a built-in way to move between windows that I was looking for a while: windmove. Turns out it’s been there since Emacs 21, which means that for me, it was there all this time, and I didn’t know about it. Windmove lets you switch between windows using the shift and arrow keys by default, so that S-up would move you one window up, while S-down will move you down. You need to enable it and then enable its default keybindings, or assign it alternative keybindings.

Looking at these key-bindings, I can see why it’s turned off by default. Shift plus an arrow key is used extensively in org-mode, for example, so you can’t use these keys. Using something else, say, C+M+left or C+M+right, is not good either because on Linux, this will “swish” your workplaces (“spaces” in macOS), while the meta key plus an arrow is also taken by something else in Emacs… you get the idea, finding the keys to use is getting a bit problematic. You need to figure out what you can give up, or find a creative shortcut that works for you specifically. However, this seems too useful to pass up, so I think I’m going to dedicate keys to it very soon.

The video also goes over windmove’s sibling, windmove-swap-states-[direction], which switches the windows in the direction you tell it. So if I am working on this post in a window that is above a list of links I’m using as reference in the window below in another buffer, I can use windmove-swap-states-down to switch. Now I will be working in the lower window, and the list of links will be in the window above. This is good if I want my list of files in Dired to the window to the right, but dired-jump-other-window opened it in the window below, for example. Nice, it saves a few C-x 0 and C-x 1 maneuvers.

Then there are the external packages, of course. ace window is probably the most popular one, and this video provides a brief demonstration of it. The idea is that it numbers the windows for you on the screen, and then you select a number to jump to a window. Another package I learned about is winum, which is built on top of this idea, but it displays the window number in the minibuffer of each window all the time, and then it’s a matter of C-x # to jump to that window. It integrates into Emacs better in my opinion, and if you use many windows, it probably makes sense. I usually have no more than four windows open at once, so using the built-in windmove is probably better.

Alright, I’m off to rebind some keys and do some tweaking! Then we will see how much I need to mess with Emacs’s built-in logic for windows placement. It might just make a little more sense now.

Footnotes

1: it’s building on dired-jump (C-x C-j), which opens dired in the directory the buffer I’m in. So, if I’m working on bills.org, which is under ~/Documents/personal/, dired-jump will open dired inside ~/Documents/personal/. The problem for me is that it will take over my current buffer (where I have bills.org open), which I don’t want; this is where dired-jump-other-window comes in: it will open Dired in a separate window.

2: this Emacs keys and windows management rabbit hole makes me re-appriciate Emacs’s default key binding. They’re there for a reason. They might not make sense at start… or maybe for several years, depending on how often and how much you use Emacs and what for, but now I see how C-x 4 is an entire family of key combinations tied to “other window” functions and then other key bindings start to make sense. For some of you veteran Emacs users, this might be obvious, but for me, that’s a slap on the forehead with a “Ohhh! So this is why this keybinding is like this!”

-1:-- Emacs' windows navigations and some Emacs zen (Post TAONAW - Emacs and Org Mode)--L0--C0--2025-05-09T15:52:38.000Z

Protesilaos Stavrou: Live @ 2025-05-11, 14:00 Europe/Athens: ‘Ask Me Anything’ about Emacs, Linux, and Life in general

Raw link: https://www.youtube.com/watch?v=0N7vshEYOok

On Sunday, the 11th of May 2025, at 14:00 o’clock of time zone Europe/Athens, I will do a live stream where I will answer every question posted in the chat. The idea is to cover any of the topics I already write/talk about on my website, including Emacs, my recently published “Emacs Lisp Elements” free book, libre software, politics, philosophy, and everyday affairs.

I will answer every question from top to bottom to the best of my abilities and will not give any of those formulaic non-answers. No tricks; no gimmicks!

The plan is to do a minimum of two hours, but may extend it for at least one or two more hours depending on the participation in the chat.

The event will be recorded: no worries if you cannot make it live.

Talk to all of you soon!

-1:-- Live @ 2025-05-11, 14:00 Europe/Athens: ‘Ask Me Anything’ about Emacs, Linux, and Life in general (Post Protesilaos Stavrou)--L0--C0--2025-05-09T00:00:00.000Z

Charles Choi: Opening the Emacs Initialization File, or First Impressions Matter

In working on the on-boarding for Scrim, I’ve recently had to consider the scenario of setting up a fresh install of GNU Emacs on macOS (as of this writing v30.1). A number of things struck me, particularly on the user experience (or lack thereof) for new users of Emacs, nearly all of whom will be unfamiliar to Emacs commands and keybindings.

  1. There is no dedicated command to load the Emacs initialization file (in this case ~/.emacs, which has yet to be created).
  2. Using the menu bar (File › Open File…) will open a macOS File Browser dialog window, but does not show hidden files (like .emacs) by default.
  3. The customize-variable command only works on variables that have been loaded.

On point 1, it’s striking to me that this hasn’t been done already like… decades ago. New users won’t know a priori what the Emacs initialization file is (sidestepping the inside baseball of .emacs vs init.el) much less that such a file is not immediately created at the first launch of Emacs but the ~/.emacs.d/ directory is.

Further exacerbating this is point 2, where the menu bar action File › Open File… will open a native macOS file dialog instead of running find-file. However this dialog is not configured to show hidden files. When the dialog is raised, the user can use the macOS key-binding Command + Shift + . to show hidden files, but this is hardly a discoverable feature.

On point 3, while I’ve long been an advocate for using customize-variable, it fails for variables that are not autoloaded (in this case server-use-tcp). A partial work-around is to run the command describe-variable which should implicitly load the package containing a non-autoloaded variable in order to describe it (although I would not be surprised if there are cases where you really have to load the package via require). Once the variable is described, a link is provided to customize it. Arguably, such details should never be surfaced to a new user.

Going back the lack of a dedicated command to load the Emacs initialization file, here’s some Elisp that implements it. Note that the variable user-init-file is already set to ~/.emacs for a fresh install.

1
2
3
4
(defun find-user-init-file ()
  "Edit `user-init-file'."
  (interactive)
  (find-file user-init-file))

For most experienced Emacs users, this command has little value but it's not meant for them. It's meant for new users and should be built-in. First impressions matter!

-1:-- Opening the Emacs Initialization File, or First Impressions Matter (Post Charles Choi)--L0--C0--2025-05-08T21:00:00.000Z

Irreal: Toggling Narrowing

Over at the Emacs subreddit, sebhoagie has a short post that some of you may find useful. Sebhoagie really likes narrowing and uses it all the time. Sometimes, though, the narrowed code refers to code outside the narrowed region and he occasionally wants to reference it and then return to the narrowed region.

That’s not a big problem of course. Just widen, search for the referenced code, highlight the original narrowed code, and renarrow. Of course there’s a bit of friction and if you need to do it often it can become a burden.

Sebhoagie has a writeup that explains his solution. The TL;DR is that he wrote a function that narrows to a region but when you widen, it remembers the narrowed region. If you narrow again (using his function) it will renarrow to the previous region and forget the saved region parameters. If you think it through, that does exactly what you want. When you’re finished with the narrowed region you simply widen in the normal way (with widen) and everything is reset.

My solution is to use Artur Malabarba’s narrow-or-widen-dwim that almost always does exactly what I want. Take a look at Malabarba’s post to see how it works. If you’re not using it, you’re definitely working too hard. Still, you may find sebhoagie’s useful. If you have a similar need, his code is a nice companion to Malabarba’s.

Narrowing really can be a superpower as sebhoagie says and it’s worthwhile making its use as easy as possible.

-1:-- Toggling Narrowing (Post Irreal)--L0--C0--2025-05-08T14:48:16.000Z

James Cash: Social Update

I’ve been using Mastodon as my only social media for a while now. I started on mastodon.social, but moved over to Fosstodon after a while, desiring a slightly smaller, more focused instance. That was fine for a while; the local timeline was actually useful and I found some people to follow from there.

Over time though, I found myself not caring so much about the local timeline and I’d occasionally see some complaints about the fosstodon moderation policies. I didn’t love that, but setting up my own Mastodon server seemed like a huge pain - demanding minimum system resources, lots of care & feeding.

Things reached a head recently though, over some more extreme issues with Fosstodon’s moderators and some people I follow had stated they would be defederating from Fosstodon immanently. Trying to find a new server that wasn’t itself going to have moderation problems sounded tiring and I don’t exactly have a lot of free time right now, but I did remember hearing more recently about GoToSocial as a Mastodon-compatible Fediverse server that was much lighter to run. I took a quick look at the setup instructions, decided that it seemed like less work than finding a “good” Mastodon server, so I spun my own instance up!

I was really impressed with how easy it was – I don’t much care for Go as a programming language, but static binaries do make installation really straight-forward – just untar, set up some config files, and I was off! I also appreciated how the installation instructions weren’t just “use Docker”; I much prefer running things without containers.

I made my own theme as well to match my blog, which was also quite straight-forward – just make a CSS file and scp it up to the appropriate directory.

I’m very happy with my new home on the Fediverse now! I also updated my “socials” footer here to have a more general “fediverse” logo instead of the Mastodon-specific one, since I’m no longer riding the elephant. It feels satisfying in this age of the internet consolidating into like four websites run by billionaires to have one’s own little corner of the internet, as cozy and kind of weird as you like it.

-1:-- Social Update (Post James Cash)--L0--C0--2025-05-08T04:00:00.000Z

James Dyer: Discovering Treasures in Emacs-solo

While exploring Emacs-solo, I was struck by how closely its philosophy aligned with my own Emacs-DIYer project. The parallels were sometimes uncanny, for example, we had independently chosen identical keybindings like “M-s g” for grep functionality. I had been also considering “M-s f” for my find variant and was looking for a home for recentf, potentially at “M-g r”. There were also some ideas around using other finding tools such as ripgrep and fd as a callout to some external tools and there were many other similarities.

I was particularly intrigued to see newsticker included, as I had recently adopted it as an elfeed replacement. The ace-window alternative implementation also closely mirrored my own single-defun approach.

So, with my first pass through, I have picked out the following goodies to be purloined and incorporated into Emacs-DIYer

  • dired icon replacements
  • Git gutter status overlay
  • Hide completion buffer when icomplete in buffer
  • ollama alternative directly from ansi-term

Firstly, the dired icon replacement provides visual clarity without requiring the all-the-icons packages. While perhaps not essential, it gives me a comfy feel and I think these icons significantly improve the Emacs experience, particularly for frequent dired users like myself.

I pretty much just copied the entire emacs-solo-dired-icons section but stripped out the use-package as I’m trying to keep Emacs-DIYer compatible with older versions of Emacs. This worked straight out the box (like all the other integrations) and I just needed to make sure I have the requisite font collection installed.


The git status indicator in the dired gutter was a welcome addition I hadn’t previously implemented or even considered. It provides immediate visual feedback that feels natural and intuitive, especially coming from a background of extensive version control experience.

Having used subversion for over 20 years (before transitioning to TortoiseSVN and then magit and vc), I was already accustomed to status characters like “M” indicating modified files and other single key status key definitions seem consistent to my previous experience, and isn’t it great to see them visible in dired!

In summary, this integration complements my existing modeline status indicator, along with vc and gives me both file-specific and directory-level version control visibility, noice!


I had been working on replacing corfu/company with in-buffer completion, but hadn’t solved how to hide the completion buffer when using icomplete. My settings already closely matched those in Emacs-solo, but the critical missing piece was this elegant advice:

(if icomplete-in-buffer
    (advice-add 'completion-at-point
                :after #'minibuffer-hide-completions))

Now it feels much cleaner and I might start using it rather than corfu from now on.


The final act of pilfering is to incorporate a simple ollama integration.

Before creating my Ollama Buddy package, I had explored integrating ollama through a shell and I had also come to the conclusion that using ansi-term was really the only quick solution, but I just couldn’t figure out the implementation details. However, the experience ultimately led me to take an alternative approach, writing a small implementation to interface with ollama from an Emacs buffer, which eventually gave rise to Ollama Buddy.

The Emacs-solo ansi-term solution feels surprisingly well-integrated once you become comfortable switching between line and character modes. I’ve now incorporated this as an alternative to my API-based implementation, providing two no-dependency options for local LLM access!

I plan to further explore Emacs-solo, particularly for additional vc enhancements. This first pass has already yielded valuable improvements to Emacs-DIYer, and this has been a valuable exercise to learn from another project with such similar design principles.

-1:-- Discovering Treasures in Emacs-solo (Post James Dyer)--L0--C0--2025-05-07T20:45:00.000Z

Org Mode requests: [FR] Adding custom indices for Texinfo export (and maybe unaffiliated dual-value keywords?)

[FR] Adding custom indices for Texinfo export (and maybe unaffiliated dual-value keywords?)
-1:-- [FR] Adding custom indices for Texinfo export (and maybe unaffiliated dual-value keywords?) (Post Org Mode requests)--L0--C0--2025-05-07T18:24:33.000Z

Jack Baty: Set point at first heading when opening Org mode file

I recently discovered Org mode’s speed keys option and it’s pretty great. One caveat with speed keys is that they only work if the point is at the very beginning of a heading. To help with this, I (with Claude’s help) created a small lisp function and hook to move the insertion point to the beginning of the first heading whenever I open an Org mode file. I’m recording it here in case it’s useful to anyone else.

(defun my/org-goto-first-heading ()
  "Move point to the beginning of the first heading in an org file."
  (when (eq major-mode 'org-mode)
    (goto-char (point-min))
    (if (re-search-forward "^\\*+ " nil t)
        (goto-char (match-beginning 0)))))

(add-hook 'org-mode-hook 'my/org-goto-first-heading)

I had to disable the saveplace package but I don’t mind. This is better, since I don’t often want to return to where I was last editing a document.

I wouldn’t be shocked to learn that there’s a simpler way to do this, but this works for now.

-1:-- Set point at first heading when opening Org mode file (Post Jack Baty)--L0--C0--2025-05-07T09:40:07.000Z

Tim Heaney: Magic completions in rust-analyzer

Today I learned rust-analyzer magic completions include tmod (test module) and tfn (test function). We get these from cargo when we start a new library, but we can stick them in anytime! Here I am typing tmod TAB and and then tfn TAB in Emacs. If your editor is configured to use rust-analyzer, it probably works similarly. Neat!
-1:-- Magic completions in rust-analyzer (Post Tim Heaney)--L0--C0--2025-05-07T00:00:00.000Z

Jeremy Friesen: Migrating to Linux: Getting Emacs Installed

With my Migrating to Linux: On Guiding Principles and Keyboard Bindings complete, I moved on to getting tool of my computering: Emacs.

I think my Emacs 📖 configuration requires at least version 29.1; however I’m uncertain. The package manager had Emacs 27 available, so I opted to build from source.

I could either download a released version’s source code or clone the repository. I chose the clone route; as this would be useful as upgrades come out.

Preliminaries:

sudo apt update && sudo apt install git --assume-yes

With git installed I need a copy of the Emacs repository, and should build from a stable ref; as of <2025-04-23 Wed> that is emacs-30.1. Sidenote I had a copy of the Emacs git repository on another machine. So I used the sneaker net (e.g. a thumbdrive) to copy that over to the Linux 📖 machine and then run git pull so I could get up to date source code.

I used Installing Emacs 29.1 from source on Debian 12 · GitHub as my framing.

First, building the dependencies:

sudo apt build-dep emacs
sudo apt install libtree-sitter-dev libgcc-12-dev libgccjit-12-dev

Then making a home for my new install:

mkdir -p ~/.local/emacs

In my source directory for Emacs (e.g., ~/git/emacs/), I ran the following:

./configure \
--prefix="$HOME/.local/emacs/" \
--without-compress-install \
--with-native-compilation=aot \
--with-x \
--with-x-toolkit=lucid \
--with-gif \
--with-png \
--with-jpeg \
--with-tiff \
--with-imagemagick \
--with-mailutils \
--with-tree-sitter \
CC=gcc-12

It took a few tries, which is why I have the CC=gcc-12 declaration as well as instructions for installing libgcc-12-dev and libgccjit-12-dev.

Now came time to spin up the fans. I ran make -j 16; where 16 is the number of cores on my machine. And finally make install.

Along the way, I realized that there were terminal commands that I was missing. But I could hobble along.

Up until I had Emacs built, I was using nano to write my notes. It is quite serviceable.

Note, I could have installed Emacs 30.1 via the Pop Shop, however I chose to build from source.

Toggling Gnome Settings

There are a few settings that I have found useful to toggle:

Trackpad and Night Light

With my new laptop and how I hold my hands, I’ve noticed that sometimes I activate my trackpad. Which is annoying, especially when I’m in a “writing mindset.”

I don’t like the bright blues of a normal screen. Instead I prefer to use a display setting that softens the colors. In Macintosh Operating System (MacOS 📖) this is “Night Shift.”

I choose a much warmer color, knowing that reds are softer on the retina. Sidenote My mom has a retinal disease and her research and recommendations from experts leads her to incorporate more red filters in her day to day.

Both of these settings are similar in how they are toggled. So I wrote some Emacs Commands for Setting Toggling.

Emacs Commands for Setting Toggling

With the toggles identified, I set about writing the functions and macros to help with future needs.

To create my Trackpad toggling command I call my jf/linux:gsettings-toggler Emacs macro. Below is the code:

(jf/linux:gsettings-toggler "Trackpad"
  :property "org.gnome.desktop.peripherals.touchpad send-events"
  :match "'enabled'"
  :on_match "disabled"
  :on_miss "enabled")

The first parameter is the named concept (e.g., “Trackpad”). The :property is the gsettings key that I’m looking to change (e.g. “org.gnome.desktop.peripherals.touchpad send-events”). The :match value is what I check as the property’s current state. When the current value is a match, I set the property to the :on_match value.

And below is how I generate my Night Light toggling command:

(jf/linux:gsettings-toggler "Night Light"
    :property "org.gnome.settings-daemon.plugins.color night-light-enabled"
    :match "true"
    :on_match "false"
    :on_miss "true")

As of <2025-05-03 Sat> the generating macro is as follows:

(cl-defmacro jf/linux:gsettings-toggler (name &key property match on_match on_miss)
    "Toggle the NAME setting via the PROPERTY.

When the PROPERTY is a MATCH set the property to ON_MATCH; otherwise set
it to the ON_MISS value."
    (let ((docstring
            (concat "Toggle " name " for Gnome desktop."))
           (func-name
             (intern (concat "jf/linux:toggle-" name))))
      `(defun ,func-name ()
         ,docstring
         (interactive)
         (let ((value
                 (if (string= ,match
                       (s-trim
                         (shell-command-to-string
                           (concat "gsettings get " ,property))))
                   ,on_match ,on_miss)))
           (shell-command
             (concat "gsettings set " ,property " " value))
           (message "%s: %s" ,name value)))))

Light/Dark Theme

Related but different from the Night Light concept is the Light and Dark theming. In Emacs I had a script to toggle the theme of both the OS and Emacs (e.g. my jf/dark function). I wanted something similar in Linux .

Yet, as I explored the changes, I realized that there would be a divergence in implementation based on MacOS or Linux .

Toggling the light and dark theme is a bit different; as this requires coordination. My jf/color-scheme-system-toggle command handles both the MacOS and my Linux install.

(defun jf/color-scheme-system-toggle ()
    "Toggle system-wide Dark or Light setting."
    (interactive)
    (pcase system-type
      ('darwin
        (progn
          (shell-command
            (concat "osascript -e 'tell application \"System Events\" "
              "to tell appearance preferences "
              "to set dark mode to not dark mode'"))
          (jf/color-scheme-set-for-emacs)))
      (_
        (let ((lightp
                (eq :dark (jf/current-color-scheme-gnome))))
          (dolist (fn jf/color-scheme-system-toggle-functions)
            (funcall fn lightp))))))

The Linux toggling portion determines if the scheme is :dark, and uses that boolean value to pass to each of the toggling functions.

My jf/color-scheme-system-toggle-functions variable (which I realized is misnamed) defines a list of functions that I’ll call, passing true when I want to set them to the “light” theme. Below is that variable’s definition:

(defvar jf/color-scheme-system-toggle-functions
    '(jf/color-scheme:gnome-color-scheme
       jf/color-scheme:gnome-gtk-theme
       jf/color-scheme:copyq-theme
       jf/color-scheme:emacs-theme)
    "A list of arity one functions that set component schemes based on the
input parameter.

When the parameter is non-nil, favor the dark option.  Otherwise favor
the light option.")

The four functions that toggle my system scheme are similar but just different enough:

Below is the definition of those four functions:

(defun jf/color-scheme:gnome-color-scheme (lightp)
  "Set the gnome color scheme based on LIGHTP (e.g. light/dark)."
  (shell-command
   (format
    "gsettings set org.gnome.desktop.interface color-scheme prefer-%s"
    (if lightp "light" "dark"))))

(defun  jf/color-scheme:gnome-gtk-theme (lightp)
  "Set the gnome gtk theme based on LIGHTP (e.g. light/dark)."
  (let ((theme
         (if lightp "Adwaita" "Adwaita-dark")))
    (shell-command
     (format
      "gsettings set org.gnome.desktop.interface gtk-theme %s"
      theme))))

(defun jf/color-scheme:copyq-theme (lightp)
  "Set the copyq theme based on LIGHTP (e.g. light/dark)."
  (shell-command
   (format
    "copyq loadTheme %s/solarized-%s.ini"
    (s-trim
     (shell-command-to-string "copyq info themes"))
    (if lightp "light" "dark"))))

(defun jf/color-scheme:emacs-theme (lightp)
  "Set the emacs theme based on LIGHTP (e.g. light/dark)."
  (ef-themes-select
   (plist-get jf/themes-plist
              (if lightp :light :dark))))

An astute reader might notice some duplication of my jf/color-scheme:gnome-color-scheme and jf/color-scheme:gnome-gtk-theme and the toggling macro. There’s a potential refactoring there, but I’m going to leave it on the idea shelf.

Radios

By default, I like to keep my Bluetooth off. I wanted a way to turn this off and on via Emacs . And also turn off and on my WiFi.

Below are my functions to go radio silent and start broadcasting:

(defun jf/linux:radio-silence ()
    "Soft block laptop radios (e.g. bluetooth and wlan).

Related to `jf/linux:radio-broadcast'."
    (interactive)
    (shell-command "rfkill block all"))

  (defun jf/linux:radio-broadcast (&optional all identifiers)
    "Soft unblock laptop radios (e.g. bluetooth and wlan)

When ALL is non-nil unblock all radios.  Other unblock only the wlan.

Related to `jf/linux:radio-silence'."
    (interactive "P")
    (let ((identifiers
            (mapconcat
              (lambda (el) el)
              (or identifiers '("wlan"))
              " ")))
      (shell-command
        (concat "rfkill unblock "
          (if all "all" identifiers)))))

I don’t have a physical switch, so I settle for the soft programmatic block.

Grabbing Links

Part of my writing workflow is grabbing links from my browser (and RSS 📖 feed). On MacOS I use GitHub - xuchunyang/grab-mac-link.el: Grab link from Mac Apps and insert it into Emacs. And I explored GitHub - xuchunyang/grab-x-link: Grab links from some X11 apps and insert into Emacs.

However, that wasn’t quite enough. So I wrote up some changes for my own needs; namely to address having multiple applications based on Firefox. Along the way I learned about xdotool and comm.

Conclusion

With Emacs installed, I could really set about my documentation process. My next article in this series will be about other applications I use: Virtual Private Networks (VPNs 📖) , browsers, terminal, and connecting to Github.

-1:-- Migrating to Linux: Getting Emacs Installed (Post Jeremy Friesen)--L0--C0--2025-05-06T20:59:14.000Z

Irreal: A Small Git Improvement For Elisp Files

James Cherti has a quick tip on configuring Git to provide more meaningful diffs for Elisp files. The problem, he says, is that by default Git diffs simply provide a line-by-line difference with no added context such as what functions are involved. It turns out that it’s pretty easy to provide that context.

The process is pretty simple. First you have to provide a regular expression that recognizes the various def constructs such as defun and defmacro. Then you tell Git to associate that regex with Elisp files. After doing that, you get a bit more context in your Git diffs.

Take a look at Cherti’s post for the details. It’s a small thing but easy to do and it may make your change analysis a bit easier.

-1:-- A Small Git Improvement For Elisp Files (Post Irreal)--L0--C0--2025-05-06T14:56:07.000Z

James Cherti: Enhancing Git Diff for Emacs Lisp: Better Git Diff of Elisp function or macro definitions

By default, the git diff algorithm compares changes in Elisp files line by line without understanding the structural semantics of Emacs Lisp files. This means that when modifications are made within functions, the diff output does not convey how those changes relate to higher-level code constructs such as functions or macros.

As a result, reviewers are presented with fragmented and often verbose diffs where the context of a change, such as which function it belongs to, is not always readily apparent. This lack of structural awareness can make it difficult to assess the purpose and impact of changes efficiently.

Git can be configured to recognize function or macro definitions explicitly, ensuring that diffs are presented at the function or macro level rather than as arbitrary line changes. Here are the steps:

Step 1 – The Git configuration for Emacs Lisp diffs

Add the following elisp Git driver to your ~/.gitconfig file:

[diff "elisp"]
xfuncname = ^\\([^[:space:]]*def[^[:space:]]+[[:space:]]+([^()[:space:]]+)

The regular expression above matches lines that begin with typical Emacs Lisp definition forms, such as defun, defmacro, and other def* constructs. It detects the symbol being defined, allowing Git to handle changes at the function or definition level intelligently. This configuration can also be found in the autogen.sh file, which is part of the Emacs source code.

Step 2 – Associating the Git Diff Driver with *.el files

Once the custom diff driver is defined, it needs to be associated with Elisp files. This is accomplished by adding the following line to the ~/.gitattributes file:

*.el diff=elisp

With this setup, Git will apply the elisp diff driver to all files with the .el extension, using the custom pattern to identify function boundaries.

Conclusion

This configuration generates diffs that focus on changes within the scope of individual function and macro definitions, rather than arbitrary lines. As a result, reviews of Emacs Lisp code become more precise and contextually relevant. Reviewers can easily identify which functions were modified, without being distracted by unrelated or excessive diffs.

Related links

-1:-- Enhancing Git Diff for Emacs Lisp: Better Git Diff of Elisp function or macro definitions (Post James Cherti)--L0--C0--2025-05-05T17:53:40.000Z

Sacha Chua: 2025-05-05 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-05-05 Emacs news (Post Sacha Chua)--L0--C0--2025-05-05T17:15:31.000Z

Irreal: Emacs For Non-Programmers

MarchZealousideal543 over at the Emacs subreddit asks a familiar question: Is it really feasible or even possible for a non-programmer to use Emacs productively? I know I write about this a lot but I find the subject fascinating. MarchZealousideal543 got steered onto Emacs by asking some AI for suggestions and apparently Emacs was the overwhelming recommendation.

There’s nothing very interesting about such questions, of course; the interest is in the comments. There’s the usual ankle biting and nonsense but a lot of the comments are excellent and tell stories of how people from all walks of life—even someone in construction—use Emacs to run their lives, careers, or businesses.

The one thing that many of them say, though, is that you should expect to spend a few weeks getting up to speed with Emacs. Those of us who have been using Emacs for decades and still consider ourselves barely up to speed can only smile. Nevertheless, they all say that the startup time is worth it and that you will soon become proficient.

The other story that came up more than once was how the secretaries at the MIT were introduced to Emacs and given a small write up on how to configure it. Because they didn’t realize they were programming, they soon were soon automating their workflows.

If, like me, you like reading about non-technical people using Emacs, take a look at this reddit post.

-1:-- Emacs For Non-Programmers (Post Irreal)--L0--C0--2025-05-05T14:39:04.000Z

Windows in Emacs probably come to you as second nature now, as it does to me, but imagine how it looks to people from the outside for a minute:

Look at the diagram on the screen. Read the explanation. Look at the “huh?” expression of David of System Crafters (awesome channel for Emacs learning by the way)… Need I say more? 😂

I love Emacs, don’t get me wrong, but when it comes to managing its windows…

-1:--  (Post TAONAW - Emacs and Org Mode)--L0--C0--2025-05-05T12:58:34.000Z

Org Mode requests: [FR] Accept nil outline path for file+olp+datetree org-capture-templates target

[FR] Accept nil outline path for file+olp+datetree org-capture-templates target
-1:-- [FR] Accept nil outline path for file+olp+datetree org-capture-templates target (Post Org Mode requests)--L0--C0--2025-05-05T05:36:40.000Z

Irreal: Searching The Web With Emacs

If you’re one of those brave folks who doesn’t mind browsing the Web from within Emacs, I just came across a package that may interest you. It’s emacs-websearch a small utility that lets you specify a term, search for it on the web, choose one of the results, and open that page in your Emacs.

That may sound a little complicated but take a look at the animated GIF at the link. It seems like a pretty nice workflow. Right now, it supports Duck Duck Go and Google but looking at the code, it would be easy to add your favorite. You can choose between using the xwidget toolkit and eaf-open-browser to display the Web page.

This is one of those small packages that mainly scratches the author’s itch but can still be useful to the rest of us. Take a look and see if it might work for you.

-1:-- Searching The Web With Emacs (Post Irreal)--L0--C0--2025-05-04T15:01:46.000Z

Christian Tietze: My Current Compilation Window Display Settings in Emacs via display-buffer-alist

For the longest time, I had my compilation buffers split to the right in a rather large window.

Until I started programming in Emacs.

Previously, I looked at LaTeX build outputs, or the static site generator’s progress. That was it. Lots of logged text, so I wanted the space.

But compiling C++ or Swift code compulsively, as I do, this got on my nerves really quick. So here’s a more normal configuration, showing compilation-mode buffers in a 25% bottom split “side window” (essentially a sidebar, but anywhere).

(defun ct/display-buffer-compilation-mode-p (buffer-name action)
  "Determine whether BUFFER-NAME is a compilation buffer."
  (with-current-buffer buffer-name
    (or
     (eq 'compilation-mode (buffer-local-value 'major-mode (current-buffer)))
     (string-match (rx "*[Cc]ompilation*")
                   buffer-name))))

(add-to-list 'display-buffer-alist
             '(ct/display-buffer-compilation-mode-p
               (display-buffer-at-bottom 
                display-buffer-in-side-window)
               (window-height . 0.25)
               (side . bottom)
               (slot . -6)))

I’m not matching for (derived-mode-p 'compilation-mode) because that also catches rg.el and ag.el buffers. (I used to auto-hide compilation buffers and got terribly confused and annoyed that my search results wouldn’t show anymore.)

I still make Emacs Lisp compile warning windows not show at all, via https://protesilaos.com/codelog/2024-11-28-basic-emacs-configuration/:

 (add-to-list 'display-buffer-alist
             '("\\`\\*\\(Warnings\\|Compile-Log\\)\\*\\'"
               (display-buffer-no-window)
               (allow-no-window . t)))

Ah, and as of today, I’ve tagged all my posts including display-buffer-alist because I’ll definitely tweak these again and again.


Hire me for freelance macOS/iOS work and consulting.

Buy my apps.

Receive new posts via email.

-1:-- My Current Compilation Window Display Settings in Emacs via display-buffer-alist (Post Christian Tietze)--L0--C0--2025-05-04T09:11:58.000Z

TAONAW - Emacs and Org Mode: Emacs window management tweaking

I didn’t sleep well last night (it was too hot and humid for what I’m used to), so as a way to quiet my brain down, I turned to Emacs tweaking as always. This time, something that’s been driving me nuts for a while: Emacs' way of managing windows.

By default, Emacs' usage of windows doesn’t make sense to me. New windows open in seemingly random places, and modes that are supposed to help with the current buffer (like help for example) start out of focus, meaning you have to switch to them (C-x b) to scroll and read. When using several windows, this mess can quickly get out of hand.

To organize Emacs windows the way I want them to, I need to play around with display-buffer-alist. By default, its value is nil— meaning Emacs does what it does by default.

Micky has a good article explaining how Emacs prioritizes its windows by default and how display-buffer-alist works, while Port has a helpful visual tutorial with examples.

I like how Prot explains that an alist is a “list of lists,” so what we’re working with here is giving Emacs lists as guides as to how to display its windows. The way it works for each list is basically:

  1. Define what is the “trigger” for a rule
  2. Define what guides or functions to follow for that trigger
  3. Define additional parameters (additional “tweaks”)

Here’s what I have so far:

    (setq display-buffer-alist
          '(
            ;; trigger: when the major mode is dired-mode:
            ((derived-mode . dired-mode)
            ;; guides: show me the above (dired) in a side window:
            (display-buffer-in-side-window)
            ;; paramaters: what side? right. How wide? .80:
            (side . right)
            (window-width . 80)
          ))
    )

This works, but it has a couple of functional problems.

  1. In general, I prefer Dired to open to the right. I want to open another Dired window. In that case, I want it to open under the existing dired window. I usually open two Dired windows when I work with dwim for file functions, like renaming/moving files from one place to another. I doubt I’ll need to open three dired windows, but if I do, the idea should be the same: keep opening more Dired windows under the existing Dired windows.

  2. The width is fixed, and I find .80 to be OK, but sometimes, this is too much, especially when the overall Emacs window (the frame) is already small. If I call Dired, I want Emacs to increase the size of the entire frame if it’s under a certain size.

  3. I want to make sure Dired doesn’t delete or occupy other existing Dired windows, since that defeats the purpose of working with dwim. Each Dired window should have its own window, as I stated above: the first to the right, and the rest under the existing ones.

I’ve already been watching videos and reading for an hour and a half, and I’m getting sleepy again, so I think I’ll attempt to fill my sleep bank some more.

-1:-- Emacs window management tweaking (Post TAONAW - Emacs and Org Mode)--L0--C0--2025-05-03T14:52:32.000Z

Org Mode requests: [FR] file+olp+datetree accepting function to select target file

[FR] file+olp+datetree accepting function to select target file
-1:-- [FR] file+olp+datetree accepting function to select target file (Post Org Mode requests)--L0--C0--2025-05-02T23:49:22.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!