Categories: geek » emacs

View topic page - RSS - Atom - Subscribe via email

2026-02-23 Emacs news

| emacs, emacs-news

: Added m-x.app examples, moved el-init to AI category, added retrospective link.

Org Mode is a big part of why I enjoy Emacs, so I'm delighted that there's a new release out (Org 9.8). Thanks to all who contributed! If you would like to help out, Ihor is looking for several volunteers who can try to reproduce bugs and do initial feedback on the new patches.

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

2026-02-16 Emacs news

| emacs, emacs-news

Lots of cool stuff this week! I'm looking forward to checking out the new futur library for async programming, and the developments around embedding graphics in a canvas in Emacs look interesting too (see the Multimedia section). Also, the discussion about making beginner configuration easier could be neat once the wrinkles are ironed out. Enjoy!

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

2026-02-09 Emacs news

| emacs, 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

2026-02-02 Emacs news

| emacs, 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

Emacs and French: Focus flycheck-grammalecte on the narrowed part of the buffer

Posted: - Modified: | emacs, french

: Fix flycheck-checkers.

After learning about French spellcheck and grammar checking from Emacs expliqué à mes enfants, I added flycheck-grammalecte to my config. Nudged by @lann@mastodon.zaclys.com, I finally got around to figuring out why my setup sometimes worked and sometimes didn't. When I checked flycheck-verify-setup, I noticed that grammalecte kept getting disabled. A little digging around showed me that it was getting disabled because of too many errors. That was because it was trying to work on my whole file instead of just the portion that I narrowed to with org-narrow-to-subtree (ooh, just noticed an org-toggle-narrow-to-subtree command). I like having all of my French journal entries in one file because I can use consult-line (which I've bound to M-g l) to quickly look up examples of where else I've used a word. So I needed to define a checker that runs only on the narrowed part of the buffer.

(defun my-flycheck-grammalecte-buffer (checker callback)
  (let* ((temp-file-name (make-temp-file "grammalecte"))
         (output-buffer (get-buffer-create temp-file-name))
         (buffer (current-buffer))
         (cmdline (delq nil `("python3"
                              ,(expand-file-name "flycheck_grammalecte.py"
                                                 grammalecte--site-directory)
                              ,(unless flycheck-grammalecte-report-spellcheck "-S")
                              ,(unless flycheck-grammalecte-report-grammar "-G")
                              ,(unless flycheck-grammalecte-report-apos "-A")
                              ,(unless flycheck-grammalecte-report-nbsp "-N")
                              ,(unless flycheck-grammalecte-report-esp "-W")
                              ,(unless flycheck-grammalecte-report-typo "-T")
                              (option-list "-f" flycheck-grammalecte-filters)
                              (eval (flycheck-grammalecte--prepare-arg-list
                                     "-f" flycheck-grammalecte-filters-by-mode))
                              (eval (flycheck-grammalecte--prepare-arg-list
                                     "-b" flycheck-grammalecte-borders-by-mode))
                              ,temp-file-name)))
         (args (mapcan (lambda (arg) (flycheck-substitute-argument arg checker)) cmdline))
         (command (flycheck--wrap-command (car args) (cdr args))))
    (write-region (buffer-string) nil temp-file-name)
    (make-process :name "grammalecte"
                  :buffer output-buffer
                  :command command
                  :sentinel
                  (lambda (process status)
                    (let ((errors (with-current-buffer (process-buffer process)
                                    (message "%s" (buffer-string))
                                    (flycheck-parse-with-patterns
                                     (buffer-string)
                                     checker
                                     (current-buffer)))))
                      (delete-file temp-file-name)
                      (kill-buffer output-buffer)
                      ;; offset
                      (funcall
                       callback
                       'finished
                       (let ((offset (save-excursion (goto-char (point-min))
                                                     (line-number-at-pos nil t))))
                         (mapcar
                          (lambda (err)
                            (let ((new-err (copy-flycheck-error err)))
                              (setf (cl-struct-slot-value 'flycheck-error 'buffer new-err)
                                    buffer)
                              (setf (cl-struct-slot-value 'flycheck-error 'line new-err)
                                    (+ (flycheck-error-line new-err)
                                       offset -1))
                              (setf (cl-struct-slot-value 'flycheck-error '-end-line new-err)
                                    (+ (flycheck-error-end-line new-err)
                                       offset -1))
                              new-err))
                          errors))))))))

(defun my-flycheck-grammalecte-setup ()
  "Build the flycheck checker, matching your taste."
  (interactive)
  (unless (grammalecte--version)
    (advice-add 'grammalecte-download-grammalecte :after-while
                #'flycheck-grammalecte--retry-setup))
  (grammalecte--augment-pythonpath-if-needed)
  (flycheck-define-generic-checker 'my-grammalecte-narrowed
    "Report Grammalecte errors, but only for the narrowed section."
    :start #'my-flycheck-grammalecte-buffer
    :modes flycheck-grammalecte-enabled-modes
    :predicate (lambda ()
                 (if (functionp flycheck-grammalecte-predicate)
                     (funcall flycheck-grammalecte-predicate)
                   t))
    :enabled #'grammalecte--version
    :verify #'flycheck-grammalecte--verify-setup)
  (setf (flycheck-checker-get 'my-grammalecte-narrowed 'error-patterns)
        (seq-map (lambda (p)
                   (cons (flycheck-rx-to-string `(and ,@(cdr p))
                                                'no-group)
                         (car p)))
                 flycheck-grammalecte--error-patterns))
  (add-to-list 'flycheck-checkers 'my-grammalecte-narrowed)
  (flycheck-grammalecte--patch-flycheck-mode-map))

After I use my-flycheck-grammalecte-setup, I can use flycheck-select-checker to select my-grammalecte-narrowed and then use flycheck-buffer to run it. Then it will underline all the number/gender agreement issues I usually have. It's nice that I can practise editing my text with this script before I run the text through an LLM (also via flycheck) for feedback on wording.

2026-01-30_22-20-20.png
Figure 1: Screenshot of grammalecte providing grammar feedback
This is part of my Emacs configuration.
View org source for this post

Emacs Carnival February 2026: Completion

Posted: - Modified: | stream, emacs

For the Emacs Carnival theme for February, let's learn more about completion together. There are all sorts of cheesy puns one can make about completion and Emacs and Valentine's Day, like "You complete me," but beyond the jokes, it's actually a really good topic to help us work with Emacs more efficiently.

First, what's the Emacs Carnival?

From Christian Tietze:

A blog carnival is a fun way to tie together a community with shared writing prompts, and marvel at all the creative interpretations of the topic of the month.

You can get a sense of previous Emacs Carnivals by checking out the previous ones:

Month Host Topic
June 2025 ctietze "Take Two"
July gnewman "Writing Experience"
August takeonrules "Your Elevator Pitch for Emacs"
September rodiongoritskov "Obscure packages"
October AndyDrop "Maintenance, server or home or garden"
November donaldh "An ode to org-babel"
December GeorgeJones "The People of Emacs"
January 2026 ctietze "This year, I'll…"

You don't have to be an expert in order to post. In fact, this is a great way for all of us (beginners and otherwise) to focus on a topic together. Let's treat it like a kind of book club where we can share our notes as we learn.

What do we mean by completion in Emacs?

Completion can make it faster to enter text and to reduce errors. You can use it to find Emacs commands even if you don't know their full names or keyboard shortcuts. You can use it to expand abbreviations or even fix the typos you usually make. You can use it when you code and when you write. I've heard some people define common abbreviations across different programming languages so they don't have to remember the differences between syntaxes, and minibuffer-completion-based interfaces like consult-ripgrep let you flip through search results astoundingly quickly.

Let's start by talking about two types of completion:

  • minibuffer completion, which happens in the small window at the bottom of the screen whenever you use M-x, find a file, etc. This is where you can type a little and then find matching options so that you don't have to remember the full names of commands or files. For lots of tips, check out Understanding Minibuffer Completion - Mastering Emacs.

    For example, here's my minibuffer for M-x using vertico for the display and marginalia for annotations on the side:

    2026-01-30_12-44-23.png
    Figure 1: Screenshot of minibuffer completion
  • in-buffer completion, like when you expand an abbreviation, insert a snippet, or fill in the rest of a variable name.

    2026-01-30_14-17-45.png
    Figure 2: Screenshot of in-buffer completion

Things I want to learn about

For example, this month, I want to…

  • Minibuffer:
    • Figure out some kind of approximate speech-based minibuffer completion for commands
    • Create a custom Org Mode link type for emacswiki and other things I refer to frequently
    • Write about the completion functions I'm using to help me learn French
  • In-buffer completion:
  • Organize tons of completion-related links from Emacs News onto EmacsWiki: Category Completion and other pages - 2026-02-28: I put them into this post for now
  • Revisit the completion-related code in my config to dust off things that I can update, remember to use, or document with gif-screencast

I'll publish my notes on my blog and I'll add them to this post as well. I'd love to check out your notes too!

How to submit your entry/entries

(Update 2026-03-01: All done now! Feel free to write about the topic if it inspires you, though; I'd love to include a link to your notes in Emacs News.)

Please e-mail me at sacha@sachachua.com or DM me via Mastodon with a link to your post(s) by February 28 so that I can add them to this post. I'm happy to link to multiple posts. For example, here are some things you might like to write about:

  • what you're thinking of figuring out (in case other people have suggestions)
  • your notes along the way
  • your current setup
  • things you're particularly proud of

Looking forward to hearing from you!

A reflection on hosting Emacs Carnival this month

This was actually my first time hosting a blog carnival. Mapping out learning is one of my favourite things to do, and I enjoyed putting together a whole list of ideas and resources that might nudge people at every level. It was a great excuse to get around to improving parts of my workflow, not that I need an excuse to tinker with Emacs. Having the target date of Feb 28 encouraged me to get my notes together and actually post them, though. I also loved reading other people's posts, and I'm looking forward to integrating so many suggestions and ideas into my workflow. I think that treating the blog carnival as an opportunity to organize something like a study group or book club worked out well. I'd be glad to host in the future.

The Emacs Carnival theme for March is already up: Mistakes and Misconceptions, hosted by Philip Kaludercic. If you'd like to try hosting, you can edit the Emacs Carnival wiki page to add your name directly.

Thanks to everyone for reading and participating!

View Org source for this post

Using Silero voice activity detection to automatically queue multiple transcriptions with natrys/whisper.el

| audio, speech-recognition, emacs

I can queue multiple transcriptions with whisper.el so that they get processed sequentially with backup audio. It catches up when I pause to think. Now I want to use Silero voice activity detection to do that kind of segmentation for me automatically.

First, I need a Python server that can print out events when it notices the start or stop of a speech segment. If I print out the timestamps, I might be able to cross-reference it someday with interestingthings. For now, even just paying attention to the end of a segment is enough for what I want to do.

Python script for printing out events
import sounddevice as sd
import numpy as np
import torch
import sys
from datetime import datetime, timedelta

SILENCE_DURATION = 500
SAMPLING_RATE = 16000
CHUNK_SIZE = 512
model, utils = torch.hub.load(repo_or_dir='snakers4/silero-vad',
                              model='silero_vad',
                              force_reload=False)

(get_speech_timestamps, save_audio, read_audio, VADIterator, collect_chunks) = utils
vad_iterator = VADIterator(model, threshold=0.5, min_silence_duration_ms=SILENCE_DURATION)

stream_start_time = None

def format_iso_with_offset(offset_seconds):
    if stream_start_time is None:
        return "PENDING"
    event_time = stream_start_time + timedelta(seconds=offset_seconds)
    return event_time.astimezone().isoformat(timespec='milliseconds')

def audio_callback(indata, frames, time, status):
    global stream_start_time
    if status:
        print(status, file=sys.stderr)
    if stream_start_time is None:
        stream_start_time = datetime.now()
    tensor_input = torch.from_numpy(indata.copy()).flatten()
    speech_dict = vad_iterator(tensor_input, return_seconds=True)
    if speech_dict:
        if "start" in speech_dict:
            print(f"START {format_iso_with_offset(speech_dict['start'])}", flush=True)
        if "end" in speech_dict:
            print(f"END {format_iso_with_offset(speech_dict['end'])}", flush=True)
try:
    with sd.InputStream(samplerate=SAMPLING_RATE,
                        channels=1,
                        callback=audio_callback,
                        blocksize=CHUNK_SIZE):
        while True:
            pass
except KeyboardInterrupt:
    print("\nStopping...")

Then I can start this process from Emacs:

(defvar my-vad-events-process nil)
(defvar my-vad-events-dir "~/proj/speech/")
(defvar my-vad-events-command `(,(expand-file-name ".venv/bin/python" my-vad-events-dir)
                                "vad-events.py"))

(defun my-vad-events-filter (proc string)
  (when (and (string-match "^END" string)
             (process-live-p whisper--recording-process))
    (message "Noticed speech turn: %s" string)
    (my-whisper-continue)))

(defun my-vad-events-ensure ()
  "Start the process if it's not already running."
  (interactive)
  (unless (process-live-p my-vad-events-process)
    (let ((default-directory my-vad-events-dir)
          (process-environment
           (cons
            (format
             "PULSE_PROP=node.description='%s' media.name='%s' node.name='%s'"
             "vad" "vad" "vad")
            process-environment)))
      (setq my-vad-events-process
            (make-process
             :name "vad-events"
             :command my-vad-events-command
             :buffer (get-buffer-create "*vad-events*")
             :stderr (get-buffer-create "*vad-events-err*")
             :filter #'my-vad-events-filter)))))

Because I added Pulse properties to the process environment, I can easily use epwgraph to rewire the input so that it gets the input from my VirtualMicSink instead of the default system audio device. (Someday I'll figure out how to specify that as the input automatically.)

Now I can press my shortcut for my-whisper-continue to start the process. As I keep talking, it will continue to record. When I pause for more than a second between sentences, then it will send that chunk to the server for transcription without me having to press another button, while still listening for more speech.

How is this different from the streaming approach that many real-time speech recognition services offer? I think this gives me a bit more visibility into and control of the process. For my personal use, I don't need to have everything processed as quickly as possible, and I'm not trying to replicate live captions. I just want to be able to look back over the last five minutes to try to remember what I was talking about. I usually have a lot of quiet time as I think through my next steps, and it's fine to have it catch up then. I also like that I can save time-stamped audio files for later processing, divided according to the speech segments. Those might be a little bit easier to work with when I get around to compositing them into a video.

This is part of my Emacs configuration.
View org source for this post