Categories: stream

RSS - Atom - Subscribe via email

YE12: Categorizing Emacs News, epwgraph, languages

| emacs, stream, yay-emacs

View in the Internet Archive, watch or comment on YouTube, or email me.

Chapters:

  • 00:41:21 epwgraph
  • 00:54:56 learning languages

Thanks for your patience with the audio issues! At some point, I need to work out the contention between all the different processes that I want to be listening to the audio from my mic. =)

In this livestream, I categorize Emacs News for 2026-04-06, show epwgraph for managing Pipewire connections from Emacs, and share some of my language learning workflows.

View Org source for this post

YE11: Fix find-function for Emacs Lisp from org-babel or scratch

| org, emacs, elisp, stream, yay-emacs

Watch on Internet Archive, watch/comment on YouTube, download captions, or email me

Where can you define an Emacs Lisp function so that you can use find-function to jump to it again later?

  • A: In an indirect buffer from Org Mode source block with your favorite eval function like eval-defun
    • C-c ' (org-edit-special) inside the block; execute the defun with C-M-x (eval-defun), C-x C-e (eval-last-sexp), or eval-buffer.

          (defun my-test-1 () (message "Hello"))
      
  • B: In an Org Mode file by executing the block with C-c C-c

      (defun my-test-2 () (message "Hello"))
    
  • C: In a .el file

    file:///tmp/test-search-function.el : execute the defun with C-M-x (eval-defun), C-x C-e (eval-last-sexp), or eval-buffer

  • D: In a scratch buffer, other temporary buffer, or really any buffer thanks to eval-last-sexp

    (defun my-test-4 () (message "Hello"))

Only option C works - it's gotta be in an .el file for find-function to find it. But I love jumping to function definitions using find-function or lispy-goto-symbol (which is bound to M-. if you use lispy and set up lispy-mode) so that I can look at or change how something works. It can be a little frustrating when I try to jump to a definition and it says, "Don't know where blahblahblah is defined." I just defined it five minutes ago! It's there in one of my other buffers, don't make me look for it myself. Probably this will get fixed in Emacs core someday, but no worries, we can work around it today with a little bit of advice.

I did some digging around in the source code. Turns out that symbol-file can't find the function definition in the load-history variable if you're not in a .el file, so find-function-search-for-symbol gets called with nil for the library, which causes the error. (emacs:subr.el)

I wrote some advice that searches in any open emacs-lisp-mode buffers or in a list of other files, like my Emacs configuration. This is how I activate it:

(setq sacha-elisp-find-function-search-extra '("~/sync/emacs/Sacha.org"))
(advice-add 'find-function-search-for-symbol :around #'sacha-elisp-find-function-search-for-symbol)

Now I should be able to jump to all those functions wherever they're defined.

(my-test-1)
(my-test-2)
(my-test-3)
(my-test-4)

Note that by default, M-. in emacs-lisp-mode uses xref-find-definitions, which seems to really want files. I haven't figured out a good workaround for that yet, but lispy-mode makes M-. work and gives me a bunch of other great shortcuts, so I'd recommend checking that out.

Here's the source code for the find function thing:

(defvar sacha-elisp-find-function-search-extra
  nil
  "List of filenames to search for functions.")

;;;###autoload
(defun sacha-elisp-find-function-search-for-symbol (fn symbol type library &rest _)
  "Find SYMBOL with TYPE in Emacs Lisp buffers or `sacha-find-function-search-extra'.
Prioritize buffers that do not have associated files, such as Org Src
buffers or *scratch*. Note that the fallback search uses \"^([^ )]+\" so that
it isn't confused by preceding forms.

If LIBRARY is specified, fall back to FN.

Activate this with:

(advice-add 'find-function-search-for-symbol
 :around #'sacha-org-babel-find-function-search-for-symbol-in-dotemacs)"
  (if (null library)
      ;; Could not find library; search my-dotemacs-file just in case
      (progn
        (while (and (symbolp symbol) (get symbol 'definition-name))
          (setq symbol (get symbol 'definition-name)))
        (catch 'found
          (mapc
           (lambda (buffer-or-file)
             (with-current-buffer (if (bufferp buffer-or-file)
                                      buffer-or-file
                                    (find-file-noselect buffer-or-file))
               (let* ((regexp-symbol
                       (or (and (symbolp symbol)
                                (alist-get type (get symbol 'find-function-type-alist)))
                           (alist-get type find-function-regexp-alist)))
                      (form-matcher-factory
                       (and (functionp (cdr-safe regexp-symbol))
                            (cdr regexp-symbol)))
                      (regexp-symbol (if form-matcher-factory
                                         (car regexp-symbol)
                                       regexp-symbol))

                      (case-fold-search)
                      (regexp (if (functionp regexp-symbol) regexp-symbol
                                (format (symbol-value regexp-symbol)
                                        ;; Entry for ` (backquote) macro in loaddefs.el,
                                        ;; (defalias (quote \`)..., has a \ but
                                        ;; (symbol-name symbol) doesn't.  Add an
                                        ;; optional \ to catch this.
                                        (concat "\\\\?"
                                                (regexp-quote (symbol-name symbol)))))))
                 (save-restriction
                   (widen)
                   (with-syntax-table emacs-lisp-mode-syntax-table
                     (goto-char (point-min))
                     (if (if (functionp regexp)
                             (funcall regexp symbol)
                           (or (re-search-forward regexp nil t)
                               ;; `regexp' matches definitions using known forms like
                               ;; `defun', or `defvar'.  But some functions/variables
                               ;; are defined using special macros (or functions), so
                               ;; if `regexp' can't find the definition, we look for
                               ;; something of the form "(SOMETHING <symbol> ...)".
                               ;; This fails to distinguish function definitions from
                               ;; variable declarations (or even uses thereof), but is
                               ;; a good pragmatic fallback.
                               (re-search-forward
                                (concat "^([^ )]+" find-function-space-re "['(]?"
                                        (regexp-quote (symbol-name symbol))
                                        "\\_>")
                                nil t)))
                         (progn
                           (beginning-of-line)
                           (throw 'found
                                   (cons (current-buffer) (point))))
                       (when-let* ((find-expanded
                                    (when (trusted-content-p)
                                      (find-function--search-by-expanding-macros
                                       (current-buffer) symbol type
                                       form-matcher-factory))))
                         (throw 'found
                                 (cons (current-buffer)
                                       find-expanded)))))))))
           (delq nil
                 (append
                  (sort
                   (match-buffers '(derived-mode . emacs-lisp-mode))
                   :key (lambda (o) (or (buffer-file-name o) "")))
                  sacha-elisp-find-function-search-extra)))))
    (funcall fn symbol type library)))

I even figured out how to write tests for it:

(ert-deftest sacha-elisp--find-function-search-for-symbol--in-buffer ()
  (let ((sym (make-temp-name "--test-fn"))
        buffer)
    (unwind-protect
        (with-temp-buffer
          (emacs-lisp-mode)
          (insert (format ";; Comment\n(defun %s () (message \"Hello\"))" sym))
          (eval-last-sexp nil)
          (setq buffer (current-buffer))
          (with-temp-buffer
            (let ((pos (sacha-elisp-find-function-search-for-symbol nil (intern sym) nil nil)))
              (should (equal (car pos) buffer))
              (should (equal (cdr pos) 12)))))
      (fmakunbound (intern sym)))))

(ert-deftest sacha-elisp--find-function-search-for-symbol--in-file ()
  (let* ((sym (make-temp-name "--test-fn"))
         (temp-file (make-temp-file
                     "test-" nil ".org"
                     (format
                      "#+begin_src emacs-lisp\n;; Comment\n(defun %s () (message \"Hello\"))\n#+end_src"
                      sym)))
         (sacha-elisp-find-function-search-extra (list temp-file))
         buffer)
    (unwind-protect
        (with-temp-buffer
          (let ((pos (sacha-elisp-find-function-search-for-symbol nil (intern sym) nil nil)))
            (should (equal (buffer-file-name (car pos)) temp-file))
            (should (equal (cdr pos) 35))))
      (delete-file temp-file))))
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