Batteries included with Emacs

Emacs has a reputation for being borderline unusable out of the box, of being bloated but somehow surprisingly bare.

This is largely a discoverability problem1. The solution the Internet has settled on seems to be “Emacs distributions” like Doom, Spacemacs or Prelude that glue together dozens (sometimes hundreds) of addons to deliver a batteries included, finely tuned and user-friendly experience from first launch. While it’s not for me, this does work great 2, and many of these packages will probably make their way into the default Emacs experience in due time.

But while modern features like built-in LSP support, faster syntax highlighting (through tree-sitter) and ligature support are still being debated in the development mailing list, the long running, slow moving train of Emacs has picked up many interesting passengers.

Emacs as shipped does a lot more than meets the eye, and external package functionality often partially replicates built in behavior.

Here is a list of useful features in emacs I use regularly that I don’t see mentioned or recommended often online. Guidelines I used to populate this list:

  • No packages, stock Emacs only.
  • No steep learning curves. Learn each feature in under two minutes or bust.
  • No gimmicks. No doctor, tetris, snake, dunnet, zone or butterfly.
  • Just the deltas. No commonly mentioned packages like flymake, doc-view, outline-minor-mode or eww/w3m. Nothing that Emacs brings up automatically or a nonspecific Google search gets you.
  • Assume a modern Emacs, 26.3+.

The list is written in the language of Emacs’ conventions. If you’re new to Emacs, here’s some extra cognitive load for you:

Emacs jargon Modern parlance
M-x Alt + x
C-x Ctrl + x
Frame Emacs window
Window split/pane
Buffer Contiguous chunk of text/data
Active Region Text selection
Region Text selection (not highlighted)
Face Font, color and display properties

OK? Let’s go.

Artist mode (M-x artist-mode)

Turn Emacs into an Ascii art based paint program. Draw (poly-)lines, rectangles and ellipses. Fill or spray.

I’m not much of an (ascii) artist, but I do use artist-mode to draw boxes when writing documentation or READMEs.

Pulse (pulse.el)

The included pulse library provides functions to flash a region of text. The most useful general application is to flash the line the cursor is on as a navigational aid or accessibility feature.

As is the annoying case with many things Emacs though, it provides all the ingredients and lights the flame but leaves the cooking to you. Here’s a simple recipe:

(defun pulse-line (&rest _)
      "Pulse the current line."
      (pulse-momentary-highlight-one-line (point)))

(dolist (command '(scroll-up-command scroll-down-command
                   recenter-top-bottom other-window))
  (advice-add command :after #'pulse-line))

Modify as needed. There’s more than one external package (beacon) that does this and more, but pulse is just fine.

Undo in region (C-/)

Limit your undoing to the active region:

There’s nothing to set up or run here. This is the default behavior of undo in Emacs.

Follow mode (M-x follow-mode)

Most monitors are much wider than they are tall. Most text files are much longer than they are wide. That’s a problem.

follow-mode shows a contiguous buffer paginated across multiple windows. The cursor flows from one window to the next.

Selective display (C-x $)

If you code with rigid indentation, you can get a quick overview of your document with set-selective-display. No mucking around with folding, outline- or hs-minor-mode regexps.

Call the command with the prefix argument set to the column to hide. Call without a prefix argument to disable.

Pretty symbols (M-x prettify-symbols-mode)

This one’s mainly for LaTeX users. Display unicode versions of math operators, greek symbols and more. M-x prettify-symbols-mode in a TeX buffer.

Figure 1: Before and after enabling prettify-symbols-mode

Figure 1: Before and after enabling prettify-symbols-mode

The equivalent in org-mode is M-x org-toggle-pretty-entities. Other major modes will have to define the replacements explicitly to get this behavior. Example with Python:

 (lambda ()
   (mapc (lambda (pair) (push pair prettify-symbols-alist))
         '(;; Syntax
           ("def" .      #x2131)
           ("not" .      #x2757)
           ("in" .       #x2208)
           ("not in" .   #x2209)
           ("return" .   #x27fc)
           ("yield" .    #x27fb)
           ("for" .      #x2200)
           ;; Base Types
           ("int" .      #x2124)
           ("float" .    #x211d)
           ("str" .      #x1d54a)
           ("True" .     #x1d54b)
           ("False" .    #x1d53d)
           ;; Mypy
           ("Dict" .     #x1d507)
           ("List" .     #x2112)
           ("Tuple" .    #x2a02)
           ("Set" .      #x2126)
           ("Iterable" . #x1d50a)
           ("Any" .      #x2754)
           ("Union" .    #x22c3)))))
Figure 2: A python-mode buffer before and after enabling prettify-symbols-mode

Figure 2: A python-mode buffer before and after enabling prettify-symbols-mode

View mode (M-x view-mode)

Provide pager-like keybindings. Makes navigating read-only buffers a breeze. Move down and up with SPC and delete (backspace) or S-SPC, half a page down and up with d and u, and isearch with s.

This is my preferred way to read code or documents as I can avoid chorded commands. Note that evil-mode doesn’t help here either, since paging is bound to C-u/d/f/b.

To that end I just hook this into read-only-mode. Prolific emacser Omar Antolin Camarena points out a built-in way to use view-mode in all read-only buffers, including ones you set read-only with C-x C-q:

(setq view-read-only t)

This is my favorite feature of the bunch, considering how much time I spend in Emacs reading things.

Cycle-spacing (M-SPC)

The cycle-spacing command is more versatile than it appears. By default, it cycles between deleting all whitespace around cursor but one, deleting all whitespace and restoring whitespace. But with a negative argument, it deletes all blank lines around the cursor. (Calling it with a negative argument is fast: Hold down Meta and hit minus and space in sequence.)

Put together, it’s doing the job of (almost) three older commands: just-one-space, delete-horizontal-space and delete-blank-lines3 This opens up the bindings C-x C-o and M-\ for more useful functions.

Indirect buffers (M-x make-indirect-buffer)

One buffer. Two windows. Two states.

This one’s for outline/org users. Do you want to see an overview of your document and the section you’re working on? M-x make-indirect-buffer or M-x clone-indirect-buffer

Here I clone an org buffer and narrow the original to get a makeshift TOC:

At this point we’re a few lines of elisp away from writing a toc-minor-mode for org files!

But the possibilities are much larger, because as the manual puts it:

The text of the indirect buffer is always identical to the text of its base buffer; changes made by editing either one are visible immediately in the other. But in all other respects, the indirect buffer and its base buffer are completely separate. They can have different names, different values of point, different narrowing, different markers, different major modes, and different local variables.

Html-fontify (M-x htmlfontify-buffer)

Reproduce the look of your emacs buffer as a html file with CSS. This is either extremely useful or useless to you!

Here is the html-fontified version of the source file of this write-up.

DWIM commands (upcase, downcase and more4)

Modern versions of Emacs provide Do-What-I-Mean versions of various editing commands: They act on the region when the region is active, and on an appropriate semantic unit otherwise. Replace upcase-word and downcase-word with upcase-dwim and downcase-dwim respectively, and you can safely eject the bindings for upcase-region and downcase-region.5

(global-set-key (kbd "M-u") 'upcase-dwim)
(global-set-key (kbd "M-l") 'downcase-dwim)
(global-set-key (kbd "M-c") 'capitalize-dwim)

DWIM is standard behavior for emacs commands even when it doesn’t say that in the name. count-words, query-replace, the list goes on. Check to see if your frequently used commands DWYM.

Unit conversion in calc (M-x calc)

It’s u c. And ' (quote) for algebraic entry: calc does a lot more with units. You can simplify, define new unit conversions and more. Hit u ? to see your options.

Symbolic computation in calc (M-x calc)

We’re skirting the “learn each feature in under two minutes or bust” rule with this one, as it deserves its own write-up, or a perusal of the manual. The general interaction paradigm is simple, though.

Let’s find a Taylor expansion of the integral of the error function:

Access algebraic routines (root finding, symbolic manipulation) in calc under the a prefix. Indefinite integration is a i, differentiation is a d, solving algebraic equations is a S and so on. (Hit a ?)

Scroll lock mode (scrollock)

What it says on the tin. Move the buffer instead of the cursor when navigating. Just press the scroll lock key or M-x scroll-lock-mode.

Tabs (M-x tab-bar-mode)

These are mentioned often, but rarely recommended. Most Emacs users find the idea of tabs in Emacs to be redundant, but will happily recommend window configuration registers, which provide similar functionality.

Tabs work great to separate projects, or work and email buffers. In principle this is equivalent to popping up a new frame and letting the window manager handle the separation, but on stacking window managers I find tabs to be much preferable.

Since there’s never one way to do something in Emacs, a secondary tab-line-mode is available that adds tabs to each window instead of frame.

Next time:

  • icomplete and fido: Incremental completion systems
  • completion-styles: Supercharge completion in the minibuffer
  • re-builder and rx: Visual regular expressions
  • orgtbl-mode: Easy table formatting everywhere
  • strokes-mode: Control emacs with mouse gestures

… and more.

  1. Coupled with some antiquated defaults. I’m not holding my breath here. ↩︎

  2. And no wonder, a staggering amount of work has gone into Doom/Spacemacs etc. Tens of thousands of man hours. ↩︎

  3. Not quite, since delete-blank-lines will leave one newline untouched. ↩︎

  4. There is of course also capitalize-dwim. Much thanks to Zachary Kanfer, the author of all three DWIM commands, for reminding me of its existence. ↩︎

  5. Unless you like working with inactive regions. In which case you’re probably an Emacs greybeard and you don’t need this write-up! ↩︎