Skip to content
HN On Hacker News ↗

Even More Batteries Included with Emacs

▲ 366 points 135 comments by signa11 4w ago HN discussion ↗

Pangram verdict · v3.3

We believe that this document is fully human-written

0 %

AI likelihood · overall

Human
100% human-written 0% AI-generated
SEGMENTS · HUMAN 5 of 5
SEGMENTS · AI 0 of 5
WORD COUNT 1,593
PEAK AI % 1% · §3
Analyzed
Jun 15
backend: pangram/v3.3
Segments scanned
5 windows
avg 319 words each
Distribution
100 / 0%
human / AI fraction
Verdict
Human
Pangram v3.3

Article text · 1,593 words · 5 segments analyzed

Human AI-generated
§1 Human · 0%

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. Note 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 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. 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+.

§2 Human · 0%

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. 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: [VIDEO: Emacs dictionary-tooltip-mode demo] 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: [VIDEO: Emacs Dired and Find-File wildcards demo] Play by play 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!

§3 Human · 1%

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: [VIDEO: Emacs ffap-menu demo] 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. [VIDEO: Find all URLs demo] Play by play 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: Searching for all URLs in the buffer (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

§4 Human · 0%

(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!

§5 Human · 0%

or diff: [VIDEO: compare-windows Emacs demo] Play by play 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: [VIDEO: compare-windows Emacs demo 2] Play by play 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: An Ediff for every season If you want something more interactive/prescribed there is also an ediff-directories, because there is an Ediff command for every occasion.