Emacs features have a discoverability problem, and we’re chipping away at it one demo at a time. The years since I wrote the last one of these have yielded more surprising and useful finds, so it’s time again for a “batteries included” report.
This is the third in a series of articles highlighting useful but lesser-known features included in Emacs.
Parts 1 & 2:
Batteries included with Emacs
More batteries included with emacs
“Lesser-known” is a subjective judgment. Roughly, it means that at the time of writing, I have seen these features mentioned fewer than five times — and often never — in the past two decades of dipping in and out of online Emacs discourse. Some of the features covered in past entries are well known and often recommended today. I claim no credit.
If you’re a new Emacs user, don’t start here. This is not a getting-started guide. You will be better served by grokking basic Emacs concepts and sticking to the most widely recommended packages. Once you’ve experienced the Emacs equivalents of thoughts like “Why didn’t anyone think to put wheels on luggage until 1990?”, this series might be more helpful.
My rule of thumb is that if you aren’t yet aware of undo-in-region, there is much low hanging fruit for the picking, and you can come back to this article after that supply has run out!
.
Veteran Emacs users tend to use some relatively niche Emacs features, but in my experience it’s always a different subset for each user. So if you’ve been around the block a few times, I promise there will still be surprises below for you as well!
Same rules as before:
No packages, stock Emacs only
No packages, stock Emacs only
No steep learning curves. Learn each feature in under five minutes or bust.
No steep learning curves. Learn each feature in under five minutes or bust.
No gimmicks. No doctor, tetris, snake, dunnet, zone, butterfly… yes, we know about dissociated-press. Let’s move on.
No gimmicks. No doctor, tetris, snake, dunnet, zone, butterfly… yes, we know about dissociated-press. Let’s move on.
Just the deltas. No commonly mentioned packages like Flymake, doc-view, outline-minor-mode, gnus or eww. Nothing that Emacs brings up automatically or a nonspecific Google search gets you.
Just the deltas. No commonly mentioned packages like Flymake, doc-view, outline-minor-mode, gnus or eww. Nothing that Emacs brings up automatically or a nonspecific Google search gets you.
Assume a modern Emacs, 28.1+. Also, if you’re new to Emacs and still reading:
Emacs jargon Modern parlance
M-x Alt + x
C-x Ctrl + x
Frame Emacs window
Window split/pane
Buffer Contiguous chunk of text/data
Point Cursor position in buffer
Active Region Text selection
Region Text selection (not highlighted)
Face Font, color and display properties
I’m Sorry.
Assume a modern Emacs, 28.1+.
Also, if you’re new to Emacs and still reading:
I’m Sorry.
Okay? Let’s go:
Dictionary on hover (M-x dictionary-tooltip-mode)
Turn on dictionary-tooltip-mode to see word meanings in tooltips when you hover over them:
Of course, tooltip-mode will need to be enabled as well, but that’s the default.
If you have local dictionaries set up, it will try those first. Note that Emacs’ dictionary can look up contemporary jargon and lingo too, usually via Wiktionary:
find-file and dired with wildcards
A surprisingly little known utility of two of the most used Emacs commands: you can use wildcards when using both find-file and dired interactively.
When finding files with find-file (C-x C-f), open multiple files at once with a wildcard like *foo*.txt.
When opening a directory with Dired, produce a custom listing of specific files by specifying a filename wildcard.
Here’s a demo where both features are used to clean up some (very) old TeX compilation artifacts and then open a bunch of LaTeX files at once:
Run Dired with a “two-level” wildcard */*_region_*: look for all files with “_region_” in their name, but only in sub-directories.
Dired produces a listing of these files. (These are temporary files created by AucTeX.)
Select them all (with dired-toggle-marks, bound to t) and delete them.
Run find-file with a wildcard, opening all TeX files in sub-directories.
Check the list of buffers to see that several TeX files have been opened.
(The command used to see the list of open buffers is consult-buffer, and the completions are displayed by Corfu.)
The fact that this is possible when calling them programmatically is evident from their function signatures. But realizing that this capability is also available during interactive use requires reading through the full docstring, and no one has the time for that!
In practice the Dired wildcard capability is superseded by a modern workflow like consult-find exported as a Dired buffer by embark-export, but this works out of the box.
You might be familiar with Emacs’ “find-file-at-point” feature, M-x ffap, that checks if the cursor is on a valid file path and offers to open it.
This is accompanied by ffap-menu, a less well known but equally handy command. ffap-menu scans the whole buffer for anything that looks like a file path or URL and presents you with all of them:
Since it offers a completing-read interface, this opens up a small universe of possibilities: you can export the list of (possibly filtered) completions into a buffer, copy or open all or any subset of them, or otherwise act on them right away with Embark.
Addendum: Listing propertized links
Many Emacs applications (like EWW) include URLs as text properties and not plain-text links, and ffap-menu misses them. Inspired by ffap-menu, I use a home-brew version that fetches such links as well.
Start with EWW showing a Wikipedia page, with imenu on the left.
Call my/search-occur-browse-url, a custom command inspired by ffap-menu
Scroll through the list of page links, and scroll through the page itself.
The enhanced version:
(defun my/search-occur-browse-url (&optional use-generic-p) “Point browser at a URL in the buffer using completion. Which web browser to use depends on the value of the variable `browse-url-browser-function’.
Also see `my/search-occur-url’.” (interactive “P”) (let ((match nil) (match-data nil) (context (lambda (beg &optional shrp) (let* ((before (string-replace “\n” “” (buffer-substring-no-properties beg (max (line-beginning-position) (- beg 30))))) (link (string-replace “\n” “” (buffer-substring-no-properties beg (point)))) (after (buffer-substring-no-properties (point) (min (line-end-position) (+ (point) 30))))) (concat (propertize ” ” ‘display ’(space :align-to 65)) (propertize (concat “…” before) ’face ’shadow) (if shrp (propertize link ‘face ’(:inherit shadow :weight bold :underline t)) link) (propertize (concat after “…”) ’face ’shadow)))))) (save-excursion (goto-char (point-min)) (while (search-forward-regexp my/search-url-regexp nil t) (push (cons (match-string-no-properties 0) (funcall context (match-beginning 0))) match-data)) (goto-char (point-min)) (while (setq match (text-property-search-forward ’shr-url nil nil)) (push (cons (prop-match-value match) (funcall context (prop-match-beginning match) ’shrp)) match-data))) (let* ((completion-extra-properties `(:annotation-function ,(lambda (cand) (concat ” ” (cdr (assoc cand match-data)))))) (url (completing-read “Browse URL: ” match-data nil t))) (if use-generic-p (browse-url-generic url) (browse-url url)))))
Compare windows (M-x compare-windows)
There are more commands for comparing buffers and files in Emacs than you can shake a stick at: there’s diff, diff-buffers, diff-backup, diff-buffer-with-file, dired-diff, vc-diff, and a whole constellation of ediff-, ediff-merge- and ediff-directories- commands. I lost count at around twenty two, and can’t remember most of them.
But my favorite diff command is the lightweight compare-windows, which does something very obvious and simple in a context-agnostic way.
It compares the text of two windows starting from their respective cursor positions, and stops at and reports the next mismatch. The two windows are the active one and whatever other-window would select. Obviously less powerful, but so much easier and faster to run than Ediff
Have you tried ediff-regions-linewise? Setting this up is a four step process, involving selecting buffers, marking regions and calling exit-recursive-edit repeatedly, an advanced command that most Emacs users should never encounter!
or diff:
Move the cursor to the beginnings of the text to compare in two windows.
M-x compare-windows
That’s it. It moves the cursors to the first mismatch and reports it.
compare-windows is only concerned with the actual text in the two windows, and not the provenance of this text. The buffer type, modification state, file, version-control status — all irrelevant! You can even compare a chunk of text in a buffer against another chunk a little further down in the same buffer by displaying it in both windows. In a silly yet effective way, it can even compare directory contents, including file attributes:
Two directories containing some similar-looking files.
Place the cursors on the same file in both windows.
M-x compare-windows
The cursors stop at the first reported mismatch, which is a file modification time here.
And yes, you can call it with a prefix argument to ignore whitespace differences.
compare-windows is what you use when you find yourself playing spot-the-difference between two views of any kind. It is my most used “diff” command.
Compare directories with Dired (M-x dired-compare-directories)
But speaking of comparing directories, Dired does (of course) provide a less hacky way to do that. M-x dired-compare-directories in Dired prompts for a directory to compare with, and marks all files whose names differ in both Dired listings. That covers the most common use case, and might be everything you need.
But we already did that with the rudimentary compare-windows. dired-compare-directories is an actual file-level comparison, so you can provide custom matching predicates involving any file attribute, like modification times or sizes. For instance,
you can mark the more recently modified version of a file with (> mtime2 mtime1),
or mark files with the same name but different sizes with (/= size1 size2)
In this example, dired-compare-directories has marked (i) files that are not common to the two listings and (ii) files with differing modification times:
If you want something more interactive/prescribed there is also an ediff-directories, because there is an Ediff command for every occasion.
Highlight buffer changes (M-x highlight-changes-mode)
While we’re on the topic of spotting differences, highlight-changes-mode is a handy way to emphasize changes to the file, and a “live” alternative to diff commands like diff-buffer-with-file:
Run the below code block syncing highlight-changes-mode with save-buffer. Now changes are highlighted until the next save.
Make some changes. Notice that added/changed text is colored differently.
Save the buffer, clearing the highlights in the process.
Repeat the last two steps a couple of times.
Visualization with highlight-changes is determined only by the mode itself, and changes are highlighted from the time the mode is turned on until it’s turned off. In general, this is not what we want. What we would like instead is to highlight unsaved changes
There is M-x highlight-compare-with-file, but this is non-ergonomic enough to the point of being unusable.
. We could do this with some finesse, or just throw in a couple of hooks:
(defun highlight-changes-mode-turn-off () (and highlight-changes-mode (highlight-changes-mode -1)))
(defun highlight-changes-auto () (when (buffer-file-name) (highlight-changes-mode-turn-on) (add-hook ’after-save-hook #’highlight-changes-mode-turn-on nil t) (add-hook ’before-save-hook #’highlight-changes-mode-turn-off nil t)))
(add-hook ’text-mode-hook #’highlight-changes-auto)
Now all changes in text-mode buffers are automatically highlighted.
The highlight-changes visualization can be customized to be more subtle, but you probably don’t want it turned on all the time nevertheless. The above hook logic can easily be turned into a minor-mode in its own right: