Emacs 31.1 adds a slew of quality-of-life features. It retires its quirky unexec dumper; there are general improvements to tree-sitter, including a much-wanted auto-installer for grammars; and much more.

Emacs 31.1 is finally out! Unlike earlier Emacs versions, there is not a singular big-bang feature in this release. From what I could gather, the new garbage collector was possibly planned for inclusion in Emacs 31.1, but it has been postponed to Emacs 32. But more on that in a future post; it’s an interesting subject.
Some of the more notable features in Emacs 31.1 are small, quality of life fixes, and one deprecation that marks the end of an era.
As always, my book, Mastering Emacs is 31% off for the next week to celebrate the release also.
The unexec/pdumper controversy and subsequent deprecation
Emacs is… not a normal application. When you compile and link it, you get temacs which is the heart of Emacs but without most of the libraries that ship with it. It’s a bare-bones Emacs with little more than the C core and the interpreter; it’s not really that useful.
To get the Emacs binary you know and love, you have to run temacs and tell it to load the standard library into memory. That is slow. There is a lot of elisp and housekeeping that has to happen. It can take several minutes and a fair bit of CPU and ram to start Emacs this way; it’s untenable.
This has been a problem that has dogged Emacs for decades. It’s not a huge deal today, but back in the day it could break the back on home computers or even shared multi-user environments if a brace of enthusiastic Emacs users all decide to launch Emacs at the same time in the morning.
The solution to this problem? Load it all in once and then literally dump the text/data/bss/etc. segments of Emacs’s memory to a new binary. Do that, and you don’t have to bootstrap all that Emacs lisp state again and again. It feels like a wrestling move almost. You corral a top-heavy Emacs into position and apply The Attitude Adjustment, body slamming Emacs into a new binary, and everything’s all set up and ready to go.
It’s a pretty boss move.
But to make this, uh, wrestling move work, Emacs depended on a number of snowflake functions in glibc. After a couple of decades of enabling this sort of bad behavior the glibc team called it quits, and Emacs had to find another way of doing it.
Daniel Colascione built a much better solution, though not everyone was happy about it, that – put simply – standardizes the serialization of Emacs’s internal structures into something that is not a 1:1 dump of its internal memory structures.
The portable dumper’s been the default for a number of years now. It was first introduced around ten years ago, and in keeping with Emacs’s long history of backwards compatibility, the old unexec dumper was kept around ostensibly for the one or two users who found the idea of a portable dumper risible or unworkable.
But now it is finally gone for good. The end of an era.
User Lisp Directory
Classic problem: you git clone or download an Emacs package somewhere and now you want it to work. But how? It’s not that trivial; there are quite a few competing ways of doing it. The simplest one is to tell users to drop their package into the user-lisp/ in your .emacs.d directory and Emacs will sort out loading and setting up autoload (so the right stuff appears in M-x.)
Minibuffer and Completions
Emacs 30.1 gained completion-preview-mode, a native “pop-up window” system not unlike Company and Corfu, but more attuned to Emacs’s own way of doing things: using the *Completions* window instead of a floating child frame like Company and friends.
Emacs 31.1 builds on that with a wide range of customizable options you’re sure to want to customize if you want to go native.
Rotating Window Layouts
M-x window-layout-rotate-clockwise (see C-x w C-h for the manifold new options) and suchlike rotate your window layouts. Another little UI winner.
Exchanging the point and mark without activating the region
I’ve talked (mostly in the my book) about how transient-mark-mode is a rather awkward one-size-fits-all that was draped over Emacs’s multitude of “region-affecting” commands, like kill-region (C-w).
So C-x C-x, that exchanges point and mark, also activates the region whether you want it to or not. Fixing the mark commands in transient mark mode is an old article of mine where I demonstrate how to do exactly that. But now there’s a builtin option to not have it do that — sweet.
Tree-sitter now offers to install its grammars for you
Two blockers work in tandem to hold back the wider adoption of tree-sitter in Emacs:
- The fact that TS demands a special major mode to work; and that said mode is often a thread-bare re-implementation of the original.
- That installing grammars, especially on Windows, is a giant pain in the neck, as you have to not only thread the needle with the exacting ABI version of the tree-sitter library itself, but also ensure you just the exacting version of each language grammar, or everything goes up in smoke.
The former is still a problem, but the latter is now mostly resolved. Emacs can now finally offer to install the right language grammar for TS modes it knows about.
Now there’s no excuse not to try out Combobulate: Structured Movement and Editing with Tree-Sitter.
and so much more
Lots of little tweaks and changes. Have a read.
Installation Changes in Emacs 31.1
unexec dumper removed.
The traditional unexec dumper, deprecated since Emacs 27, has been
removed.
The portable dumper now works on m68k a.out targets.
As I wrote in the introduction at the top, this is indeed the end of an era.
Emacs's old 'ctags' program is no longer built or installed.
You are encouraged to use Universal Ctags <https://ctags.io/> instead.
For now, to get the old 'ctags' behavior you can can run 'etags --ctags'
or use a shell script named 'ctags' that runs 'etags --ctags "$@"'.
If you’re a TAGS user you should check with where and make sure you’ve got a newer one installed. (If you don’t know if you use TAGS, you do not.)
Changed GCC default options on 32-bit x86 systems.
When using GCC 4 or later to build Emacs on 32-bit x86 systems,
'configure' now defaults to using the GCC options '-mfpmath=sse' (if the
host system supports SSE2) or '-fno-tree-sra' (if not). These GCC
options work around GCC bug 58416, which can cause Emacs to behave
incorrectly in rare cases.
New configure option '--with-systemduserunitdir'.
This allows specifying the directory where the user unit file for
systemd is installed; the default is '${prefix}/usr/lib/systemd/user'.
You can tell Emacs to install a systemd service to run Emacs’s server that way. I recommend doing this.
Startup Changes in Emacs 31.1
In compatible terminals, 'xterm-mouse-mode' is turned on by default.
For these terminals the mouse will work by default. A compatible
terminal is one that supports Emacs setting and getting the OS selection
data (a.k.a. the clipboard) and mouse button and motion events. With
'xterm-mouse-mode' enabled, you must use Emacs keybindings to copy to the
OS selection instead of terminal-specific keybindings.
You can keep the old behavior by customizing 'xterm-mouse-mode' to nil.
Most people do not know this but Emacs added mouse support to terminal Emacs years ago but left it off. Terminal capabilities vary widely so that was a nice and safe decision. But now it just works as you’d expect it to: menus are clickable and so forth. Good stuff.
site-start.el is now loaded before the user's early init file.
Previously, the order was early-init.el, site-start.el and then the
user's regular init file, but now site-start.el comes first. This
allows site administrators to customize things that can normally only be
done from early-init.el, such as adding to 'package-directory-list'.
If you’re on a single user system like your laptop or home computer, this is unlikely to matter much to you.
New User Lisp directory feature.
If you have a subdirectory "user-lisp/" in your Emacs configuration
directory, then Lisp files in it and any subdirectories are now
recursively byte-compiled, scraped for autoload cookies and added to
'load-path'.
You can disable the feature by setting 'user-lisp-auto-scrape' to nil,
and you can customize the option 'user-lisp-directory' to process some
other directory instead. There is also a new command
'prepare-user-lisp' that you can invoke at any time. See the Info node
"(emacs) User Lisp Directory" for more details.
Oh this is so useful. I have been cargo culting the same snippets of code around for 23 years to load directories with my stuff in it; yes use-package helps but it’s still a lot of manual hassle. About time!
The first client frame now shows warnings from daemon startup.
When there are warnings emitted during Emacs startup, usually due to
problems in your initialization file, these are shown in a "*Warnings*"
buffer. Until now such warnings were not made visible in the case that
Emacs was started as a daemon. Now the first frame after daemon startup
will show the "*Warnings*" buffer. So for example, starting Emacs with
a command like 'emacsclient -a "" -c' will now show "*Warnings*" just
like a plain invocation of 'emacs' would.
Bad news. Emacs’s insistence on telling you about every minor stubbed toe in some random package will now plague you even if you’re running Emacs as a daemon. Such a cursed feature. Nobody cares. If it was important it’d be an error.
Changes in Emacs 31.1
'line-spacing' now supports specifying spacing above the line.
Previously, only spacing below the line could be specified. The user
option can now be set to a cons cell to specify spacing both above and
below the line, which allows you to vertically center text.
This is a global value to all of Emacs, it’s not a face setting, so you cannot use M-x customize-face to change it. Set it with setopt or customize ui.
New face 'margin' for the window margin display.
A new basic face 'margin' is used by default for text displayed in the
left and right margin areas, which are used by various packages for
per-line annotations. Its background defaults to the frame default
background, so existing behavior is unchanged for users who do not
customize this new face.
Display strings shown in the margins now inherit unspecified face
attributes from the 'margin' face, if the string itself does not fully
specify its face. If your code relied on the face of the underlying
buffer text to serve as a default for any unspecified face attributes of
strings displayed in the margin, you must now apply those face
attributes to the margin string itself using 'propertize'.
'prettify-symbols-mode' attempts to ignore undisplayable characters.
Previously, such characters would be rendered as, e.g., white boxes.
'standard-display-table' now has more extra slots.
'standard-display-table' has been extended to allow specifying glyphs
that are used for borders around child frames and menu separators on TTY
frames.
Call the command 'standard-display-unicode-special-glyphs' to set up
the 'standard-display-table's extra slots with Unicode characters. See
the documentation of that command to see which slots of the display table
it changes.
Child frames are now supported on TTY frames.
This supports use-cases like Posframe, Corfu, and child frames acting
like tooltips. To enable tooltips on TTY frames, call 'tty-tip-mode'.
The presence of child frame support on TTY frames can be checked with
'(featurep 'tty-child-frames)'.
Recent versions of Posframe and Corfu are known to use child frames on
TTYs if they are supported.
This is a welcome change for terminal users. Frames in the terminal do not work as they do in GUI — they behave more like tmux/screen “windows”. Here child frames are just inset popups like the ones you find in GUI Emacs.
Several font-lock face variables are now obsolete.
The following variables are now obsolete: 'font-lock-builtin-face',
'font-lock-comment-delimiter-face', 'font-lock-comment-face',
'font-lock-constant-face', 'font-lock-doc-face',
'font-lock-doc-markup-face', 'font-lock-function-name-face',
'font-lock-keyword-face', 'font-lock-negation-char-face',
'font-lock-preprocessor-face', 'font-lock-string-face',
'font-lock-type-face', 'font-lock-variable-name-face', and
'font-lock-warning-face'.
These variables contributed both to confusion about the relation between
faces and variables, and to inconsistency when major mode authors used
one or the other (sometimes interchangeably). We always recommended
using faces directly, and not creating variables going by the same name.
If you have customized these variables, you should now customize the
corresponding faces instead, using something like:
M-x customize-face RET font-lock-string-face RET
If you have been using these variables in Lisp code (for example, in
font-lock rules), simply quote the symbol, to use the face directly
instead of its now-obsolete variable.
Note this is not about the faces but about variables named the same as the faces. Yeah that is confusing. Emacs has faces like font-lock-string-face that you probably have customized already. But it also has variables named the same as the faces. The variables are deprecated.
If you have configured your faces with M-x customize-face (you should!) you have nothing to worry about.
New char-table 'special-mirror-table' for mirroring special glyphs.
This char-table is used to mirror special glyphs (truncation and
continuation) when the user has defined an alternative representation
for those characters via display tables.
find-func.el commands now have history enabled.
The 'find-function', 'find-library', 'find-face-definition', and
'find-variable' commands now allow retrieving previous input using the
usual minibuffer history commands. Each command has a separate history.
Huh. I never noticed they did not have their own history; now they do. That is good to know I guess but unlikely to affect me much.
New minor mode 'find-function-mode' replaces 'find-function-setup-keys'.
The new minor mode defines the keys at a higher precedence level than
the old function, one more usual for a minor mode. To restore the old
behavior, customize 'find-function-mode-lower-precedence' to non-nil.
You’re unlikely to have much of a need to customize this.
'find-function' can now find 'cl-defmethod' invocations inside macros.
New minor mode 'prettify-special-glyphs-mode'.
The new minor mode prettifies the special character glyphs (truncation
and continuation) on TTY frames (and GUI frames without fringes). You
can customize the associated new face 'special-glyphs'.
Minibuffer and Completions
Support for immediate display of the "*Completions*" buffer.
Whenever a minibuffer with completion is opened, then if the completion
table sets the 'eager-display' completion property to non-nil, the
"*Completions*" buffer will now be displayed immediately. This property
can be overridden for different completion categories by customizing
'completion-category-overrides'. Alternatively, the new user option
'completion-eager-display' can be set to t to force eager display of
"*Completions*" for all minibuffers, or nil to suppress this for all
minibuffers.
Support for updating "*Completions*" as you type.
If the "*Completions*" buffer is displayed and the completion table sets
the completion property 'eager-update' to non-nil, then the
"*Completions*" buffer will be updated as you type. This property can
be overridden for different completion categories by customizing
'completion-category-overrides'. Alternatively, the new user option
'completion-eager-update' can be set to t to make "*Completions*" always
be updated as you type, or nil to suppress this always. Note that for
large or inefficient completion tables, this can slow down typing.
'RET' chooses the completion selected with 'M-<UP>/M-<DOWN>'.
If a completion candidate is selected with 'M-<UP>' or 'M-<DOWN>',
typing 'RET' will exit completion with that candidate as the result.
This works both in minibuffer completion and for in-buffer completion.
This feature supersedes 'minibuffer-completion-auto-choose', which
previously provided similar behavior; that variable is now nil by
default.
This goes hand in hand with the changes in Emacs 30.1 to make Emacs’s minibuffer completion system behave a little bit more like traditional company/corfu-style completers.
I really rate these new inclusions but I do warn they require a fair bit of customization to really get them to behave like something that does not get in your way.
Support for completion category inheritance.
You can now define completion categories that inherit properties from
existing categories, using the new function 'define-completion-category'.
New optional value of 'minibuffer-visible-completions'.
If the value of this option is 'up-down', only the '<UP>' and '<DOWN>'
arrow keys move point between candidates shown in the "*Completions*"
buffer display, while '<RIGHT>' and '<LEFT>' arrows move point in the
minibuffer.
New user option 'completion-pcm-leading-wildcard'.
This option configures how the partial-completion style does completion.
It defaults to nil, which preserves the existing behavior. When it is
set to t, the partial-completion style behaves more like the substring
style, in that the input can match a candidate anywhere in the candidate
string.
Another minor tweak to a completion style to make it behave more like something it once did. Emacs has a diverse set of completion styles. The default have changed a lot over the years, sometimes to the chagrin of people who were used to the quirks of a now-relegated default style. For example there’s both an emacs21 and an emacs22 completion style in completion-styles-alist. But see Understanding Minibuffer Completion for more information.
'completion-styles' now can contain lists of bindings.
In addition to a symbol naming a completion style, an element of
'completion-styles' can now be a list of the form '(STYLE ((VARIABLE
VALUE) ...))' where STYLE is a symbol naming a completion style.
VARIABLE will be bound to VALUE (without evaluating it) while the style
is executing. This allows multiple references to the same style with
different values for completion-affecting variables like
'completion-pcm-leading-wildcard' or 'completion-ignore-case'. This
also applies to the styles configuration in
'completion-category-overrides' and 'completion-category-defaults'.
Oh man. That is niche. completion-styles is a shopping list of how Emacs must match things in stuff like the minibuffer’s completer. Now you can make it so initials ignores case but substring does not.
Navigating "*Completions*" now accommodates 'completions-format'.
When 'completions-format' is set to 'vertical', typing 'n', 'TAB' or
'M-<DOWN>' in the "*Completions*" buffer (the latter also in the
minibuffer) now moves point to the completion candidate in the next line
in the current column, and wraps to the next column after the last
completion candidate of the current column. Likewise, typing 'p',
'S-TAB' or 'M-<UP>' moves point to the completion candidate in the
previous line or wraps to the previous column. Previously, these keys
ignored the vertical format, i.e., they moved point only to the item in
the same line of the next or previous column, in accordance with the
default horizontal format. In the vertical format, typing '<LEFT>' and
'<RIGHT>' in the "*Completions*" buffer (and when
'minibuffer-visible-completions' is non-nil, also in the minibuffer)
moves point only within the current line, analogously to how, in the
horizontal format, '<DOWN>' and '<UP>' move point only within the
current column.
You’ll want to configure this for sure if you are intent on using the Completions buffer and window for in-buffer completion. I always found navigating between the tabular structure in completions to be a bit weird and offputting; it’s a good use of space, for sure, but a flat list of matches is much easier to reason about.
Selected completion candidate is preserved across "*Completions*" updates.
When the window point is on a completion candidate in the
"*Completions*" buffer (because of 'minibuffer-next-completion' or for
any other reason), it will remain on that candidate after the "*Completions*"
is updated with a new list of completions. The candidate is deselected
when the "*Completions*" buffer is hidden.
"*Completions*" is now displayed faster when there are many candidates.
As before, if there are more completion candidates than can be displayed
in the current frame, only a subset of the candidates is displayed.
This process is now faster: only that subset of the candidates is
actually inserted into "*Completions*" until you run a command which
interacts with the text of the "*Completions*" buffer. This
optimization only applies when 'completions-format' is 'horizontal' or
'one-column'.
New user option 'crm-prompt' for 'completing-read-multiple'.
This option configures the prompt format of 'completing-read-multiple'.
By default, the prompt indicates to the user that the completion command
accepts a comma-separated list. The prompt format can include the
separator description and the separator string, which are both stored as
text properties of the 'crm-separator' regular expression.
It’s a pretty rare feature, that. You can “toggle-select” multiple matches from the minibuffer; few things use it, to be honest. I find the user experience rather poor if I am perfectly honest, no matter the completer. Helm is one of the few tools I think that does it well.
For a practical example of multi-select see Fuzzy Finding with Emacs Instead of fzf.
New user option 'completion-preview-sort-function'.
This option controls how Completion Preview mode sorts completion
candidates. If you use this mode together with an in-buffer completion
popup interface, such as the interfaces that the GNU ELPA packages Corfu
and Company provide, you can set this option to the same sort function
that your popup interface uses for a more integrated experience.
('completion-preview-sort-function' was already present in Emacs 30.1,
but as a plain Lisp variable, not a user option.)
New user option 'completion-preview-inhibit-functions'.
This option provides fine-grained control over Completion Preview mode
activation. You can use it to specify arbitrary conditions in which to
inhibit the mode's operation.
Another thing you’ll want to customize. You may want certain movement commands like those used in paredit or combobulate commands to not trigger the completion window.
New mode 'minibuffer-nonselected-mode'.
This mode, enabled by default, directs attention to the active
minibuffer window in the case the minibuffer window is no longer
selected, but still waiting for input. This uses the new
'minibuffer-nonselected' face.
I like this. I am glad it is enabled by default; it can be a little bit confusing not having a selected/non-selected state.
'read-multiple-choice' now uses the minibuffer to read a character.
It still can use 'read-key' when the variable
'read-char-choice-use-read-key' is non-nil.
'map-y-or-n-p' now uses the minibuffer to read a character.
It still can use 'read-key' when the variable
'y-or-n-p-use-read-key' is non-nil.
Ugh. They mucked around with the default method used for answering “yes or no” prompts in Emacs to make it more like a regular minibuffer thing instead and it caught me out by surprise some years ago when they did that, and it was a pain to track down. Keep you eye on this one if you’re of a similar mind to me on this.
'flex' completion style rewritten to be faster and more accurate.
Completion and highlighting use a new, superior algorithm. For example,
pattern "scope" now ranks 'elisp-scope-*' functions well above
'dos-codepage' and 'test-completion'. Pattern "botwin" finds
'menu-bar-bottom-window-divider' before 'ibuffer-other-window'.
Flex matching is an ido-mode feature, and I believe this is strictly speaking a reimplementation of it for the fido-mode completer built on the “new” minibuffer completion system. See Introduction to Ido Mode for IDO mode; and Understanding Minibuffer Completion for the latter.
Mouse
New mode 'mouse-shift-adjust-mode' extends selection with 'S-<mouse-1>'.
When enabled, you can use the left mouse button with the '<Shift>' modifier
to extend the boundaries of the active region by dragging the mouse pointer.
Cool. I rarely drag-select stuff in Emacs, but for finicky stuff it does actually work faster than a keyboard if it’s a one-off.
'context-menu-mode' now includes a "Send to..." menu item.
The menu item enables sending current file(s) or region text to external
(non-Emacs) applications or services. See send-to.el for customizations.
Oh my this is great. M-x context-menu-mode itself is a reasonably new feature itself (Emacs 28) and is not on by default. It adds contextual right-click menus to stuff. I have not kept abreast with all the places it has had custom commands added to it, and as the default is a bit… barebones, I can imagine most people bounced right off.
You can manually trigger the context menu mode (minor mode active or not) with M-x context-menu-open.
The mouse now drags lines in character increments again.
Dragging a horizontal or vertical line like the mode line or the lines
dividing side-by-side windows now happens in increments of the
corresponding frame's character size again. This is the behavior
described in the manual and was the default behavior before
'window-resize-pixelwise' was added for Emacs 24.1. To drag in pixel
increments, as with Emacs 24 through Emacs 30, customize
'window-resize-pixelwise' to t.
Windows
New commands to modify window layouts of frames.
'window-layout-rotate-clockwise' ('C-x w r <RIGHT>') and its counterpart
'window-layout-rotate-anticlockwise' ('C-x w r <LEFT>') rotate an entire
window layout.
'window-layout-flip-topdown' ('C-x w f <DOWN>', 'C-x w f <UP>') and
'window-layout-flip-leftright' ('C-x w f <LEFT>', 'C-x w f <RIGHT>')
flip the window layout vertically and horizontally.
'window-layout-transpose' ('C-x w t') reorganizes windows such that
every horizontal split becomes a vertical split and vice versa.
'rotate-windows' ('C-x w o <RIGHT>') and its counterpart
'rotate-windows-back' ('C-x w o <LEFT>') rotate windows in cyclic
ordering.
Oh I love this. But I’ll probably just pick one direction, clockwise or whatever, and bind that to an easy-to-reach key and suffer the indignity of tapping a few times. It is not often I wish to do this sort of thing. I’m a bit curious though because I am guessing the implementation will cycle through all nodes (Emacs’s window tiling window splits are represented as a tree structure) in the tree — try M-: (window-tree) to see the internal representation.
New user option 'rotate-windows-change-selected'.
This controls whether 'rotate-windows' and 'rotate-windows-back' change
the selected window. If nil, the selected window does not change.
The default is t, which means the new selected window will be the one
that winds up at the location of the previously-selected window.
Rotate windows but not move with it? Not for me, thanks.
New user option 'transpose-dedicated-windows'.
This controls how functions transposing or rotating windows handle
dedicated windows. The default is nil, which causes these function to
signal an error if they encounter a dedicated window.
Yeah you’ll want this at nil; dedicated windows are sticky windows. Rotating them around is probably not what you intend — or maybe it is, if you have a peculiar workflow.
Windmove commands now move to skipped windows if invoked twice in a row.
The new user option 'windmove-allow-repeated-command-override' controls
this behavior: if it is non-nil, invoking the same windmove command twice
overrides the 'no-other-window' property, allowing navigation to windows
that would normally be skipped. The default is t; customize it to nil
if you want the old behavior.
C-x o taps through windows as you probably know. But you can flag a window (see Demystifying Emacs’s Window Manager) as no-other-window so it is exempt from that command. Windmove of course lets you move between windows using your arrow keys.
New hook 'window-deletable-functions'.
This abnormal hook gives its client a way to save a window from being
deleted implicitly by functions like 'kill-buffer', 'bury-buffer' and
'quit-restore-window'.
Emacs always had a weird, disconnected relationship between buffers and windows, as anybody who has ever tried to tame the window manager (see previously mentioned article) so this feels like another patch on top of what is a pretty irreconcilable problem: how do you keep two things that can be interchanged easily from manipulating something the user/package does not want it to? With more hooks, it seems…
Buffer-local window change functions now run in their buffers.
Running the buffer-local version of each of the abnormal hooks
'window-buffer-change-functions', 'window-size-change-functions',
'window-selection-change-functions' and 'window-state-change-functions'
will make the respective buffer temporarily current while running the
hook.
'window-buffer-change-functions' is run for removed buffers too.
The buffer-local version of 'window-buffer-change-functions' may now be
run twice: once for the buffer removed from the window and once for the
buffer now shown in that window.
New user option 'quit-window-kill-buffer'.
This option specifies whether 'quit-window' should preferably kill or
bury the buffer shown by the window to quit. The default is nil.
Customize it to t to always kill the buffer; customize to a list of
major modes to kill if the buffer's major mode is one of those.
New user option 'kill-buffer-quit-windows'.
This option has 'kill-buffer' call 'quit-restore-window' to handle the
further destiny of any window showing the buffer to be killed.
'split-window' can optionally resurrect deleted windows.
A new optional argument REFER of 'split-window' makes it possible to,
instead of making a new window object, reuse an existing, deleted one.
This can be used to preserve the identity of windows when swapping or
transposing them.
New window parameter 'quit-restore-prev'.
This parameter is set up by 'display-buffer' when it detects that the
window used already has a 'quit-restore' parameter. Its presence gives
'quit-restore-window' a way to undo a sequence of buffer display
operations more intuitively.
'quit-restore-window' handles new values for BURY-OR-KILL argument.
The values 'killing' and 'burying' are like 'kill' and 'bury' but assume
that the actual killing or burying of the buffer is done by the caller.
New user option 'quit-restore-window-no-switch'.
With this option set, 'quit-restore-window' will delete its window more
aggressively rather than switching to some other buffer in it.
Ahem yeah - as above. All these things are just ointment balmed on Emacs to try and solve an intractable problem. If you let a window host anything, and a buffer jump around and open anywhere (either mechanically or by the whim of the user) then… how do you lock it down properly if you want something IDE-like?
I like the idea of these things. And I predict few will ever really make use of them, even in packages.
The user option 'display-comint-buffer-action' has been removed.
It has been obsolete since Emacs 30.1. Use '(category . comint)'
instead. Another user option 'display-tex-shell-buffer-action' has been
removed too, for which you can use '(category . tex-shell)'.
Nothing much to worry about.
New user option 'split-window-preferred-direction'.
Functions called by 'display-buffer' split the selected window when they
need to create a new window. A window can be split either vertically
(one below the other) or horizontally (side by side). This new option
determines which direction will be tried first in the case that both
directions are possible according to the values of
'split-width-threshold' and 'split-height-threshold'. The default value
is 'longest', which means to prefer to split horizontally if the
window's frame is a "landscape" frame, and vertically if it is a
"portrait" frame. (A frame is considered to be portrait if its vertical
dimension in pixels is greater or equal to its horizontal dimension,
otherwise it is considered to be landscape.) Previous versions of Emacs
always tried to split vertically first, so to get the previous behavior,
you can customize this option to 'vertical'. The value 'horizontal'
always prefers the horizontal split.
Good news if you hated the random nature of window splits. Now you’ll have a little bit of control over which direction at least. I recommend you make a note of this and if you find it aggravating that it splits things the wrong way, do set it.
The default value of 'split-width-threshold' is reduced from 160 to 150.
We believe that, after splitting, text filled to 75 columns remains
comfortable to read.
No arguments here.
New optional argument INDIRECT for 'get-buffer-window-list'.
With this argument non-nil, 'get-buffer-window-list' will include in the
return value windows whose buffers share their text with BUFFER-OR-NAME.
New 'display-buffer' action alist entry 'reuse-indirect'.
With such an entry, 'display-buffer-reuse-window' may also choose a
window whose buffer shares text with the buffer to display.
Indirect buffers are a power user feature. If you want to do separate things in the same buffer, you can split and “point” your new window to an already-visited buffer in another window, but then you’ll run into awkward things like shared major modes, the point not always remembering the right place you were because of how points and windows work. An indirect buffer points to a base buffer that you clone from; it is the same underlying text, but everything else is separate (like major mode)
New variable 'window-state-normalize-buffer-name'.
When bound to non-nil, 'window-state-get' will normalize 'uniquify'
managed buffer names by removing 'uniquify' prefixes and suffixes. This
helps to restore window buffers across Emacs sessions.
New action alist entry 'this-command' for 'display-buffer'.
You can use this in 'display-buffer-alist' to match buffers displayed
during the execution of particular commands.
That’s really cool, but will it work well if you trigger stuff through stuff like magit’s gnarly dispatchers or orgs’?
New command 'other-window-backward' ('C-x O').
This moves in the opposite direction of 'other-window' and is for its
default keybinding consistent with 'repeat-mode'.
No more need for using the negative prefix argument to go backwards.
New functions 'combine-windows' and 'uncombine-window'.
'combine-windows' is useful to make a new parent window for several
adjacent windows and subsequently operate on that parent.
'uncombine-window' can then be used to restore the window configuration
to the state it had before running 'combine-windows'.
I wonder how this fits into atomic windows which are another way of ‘combining’ windows. I am sure there is a substantial difference, perhaps because this one is not tied at all to display-buffer-alist.
New function 'window-cursor-info'.
This function returns a vector of pixel-level information about the
physical cursor in a given window, including its type, coordinates,
dimensions, and ascent.
Frames
New function 'frame-deletable-p'.
If this function returns nil, the following call to 'delete-frame' might
fail to delete its argument FRAME or might signal an error. It is
therefore advisable to use this function as part of a condition that
determines whether to call 'delete-frame'.
New function 'frame-use-time'.
This function is the frame equivalent of the function 'window-use-time'
for a window. The result is the 'window-use-time' of the frame's most
recently used window.
New functions 'get-mru-frames' and 'get-mru-frame'.
'get-mru-frames' returns a list of frames sorted by their most recent
use time, among all frames, or among those visible or iconified on the
same terminal as the selected frame. Child frames can be excluded. A
single frame can be excluded (e.g. the selected frame). 'get-mru-frame'
returns the single most recently used frame.
After deleting, 'delete-frame' now selects the most recently used frame.
Previously, after deleting a specified frame, 'delete-frame' would
select the oldest visible frame on the same terminal. To revert to the
old behavior, set the new user option 'delete-frame-choose-selected'
to nil.
I am not a massive frame user as I never found the customization to make it work the way I liked it worth the effort, even though I do also use a tiling WM. But returning to the last seen frame does seem like an odd thing to only add now; this will no doubt restore the same of people who prefer frame-only approaches to windows.
New value 'force' for user option 'frame-inhibit-implied-resize'.
This will inhibit implied resizing while a new frame is made. It can be
useful on tiling window managers where the initial frame size should be
specified by external means.
New user option 'alter-fullscreen-frames'.
This option is useful to maintain a consistent state when attempting to
resize fullscreen frames. It defaults to 'inhibit' on NS builds which
means that a fullscreen frame will not change size. It defaults to nil
everywhere else, which means that the window manager is supposed to
either resize the frame and change the fullscreen status accordingly, or
keep the frame size unchanged. The value t means to first reset the
fullscreen status and then resize the frame.
New functions to set frame size and position in one compound step.
'set-frame-size-and-position' sets the new size and position of a frame
in one compound step. Both size and position can be specified as with
the corresponding frame parameters 'width', 'height', 'left' and 'top'.
'set-frame-size-and-position-pixelwise' is similar but has a more
restricted set of values for specifying size and position.
New commands 'split-frame' and 'merge-frames'.
'split-frame' moves a specified number of windows from an existing frame
to a newly-created frame. 'merge-frames' merges all windows from two
frames into one of these frames and deletes the other one.
Frames can now be renamed to "F" on text terminals. Unlike with other frame names, an attempt to rename to "F" signals an error when a frame of that name already exists.
As I mentioned earlier frames in terminal Emacs are really just another way of doing a window configuration / screen-style “window pane”.
New frame parameters 'cloned-from' and 'undeleted'.
The frame parameter 'cloned-from' is set to the frame from which the new
frame is cloned using the command 'clone-frame'.
The frame parameter 'undeleted' is set to t when a frame is undeleted
using the command 'undelete-frame'.
These are useful if you need to detect a cloned or undeleted frame in
hooks like 'after-make-frame-functions' and
'server-after-make-frame-hook'.
Frames now have unique ids and the new function 'frame-id'.
Each non-tooltip frame is assigned a unique integer id. This allows you
to unambiguously identify frames even if they share the same name or
title. When 'undelete-frame-mode' is enabled, each deleted frame's id
is stored for resurrection. The function 'frame-id' returns a frame's
id (in C, use the frame struct member 'id').
New commands 'select-frame-by-id', 'undelete-frame-by-id'.
The command 'select-frame-by-id' selects a frame by ID and undeletes it
if deleted. The command 'undelete-frame-by-id' undeletes a frame by its
ID. When called interactively, both functions prompt for an ID.
Mode Line
New definitions for mode line faces on dark backgrounds.
The faces 'mode-line' and 'mode-line-highlight' now have separate
definitions for dark backgrounds. Previously, these two faces looked
the same with both light and dark background modes. To get the previous
visuals for these two faces, customize them to have the colors "grey75"
and "grey40", respectively, regardless of the background mode.
New user option 'mode-line-collapse-minor-modes'.
This is a new, built-in facility to hide minor mode lighters. If
non-nil, minor mode lighters on the mode line are collapsed into a
single button. The value can also be a list to specify minor mode
lighters to hide or show. The default value is nil, which retains the
previous behavior of showing all minor mode lighters.
One of my earliest articles was Hiding and replacing modeline strings with clean-mode-line. It’s been an issue as long as mode authors have had a say in how loud their mode line lighters should be.
Glad it is finally built in. No word on whether it plugs into :delight / :diminish in use-package.
New user option 'mode-line-modes-delimiters'.
This option allows changing or removing the delimiters shown around
the major mode and list of minor modes in the mode line. The default
retains the existing behavior of using parentheses.
New minor mode 'mode-line-invisible-mode'.
This minor mode makes the mode line of the current buffer invisible.
The command 'mode-line-invisible-mode' toggles the visibility of the
current-buffer's mode line. The default is to show the mode line of
every buffer.
People do ask for this all the time, so it’s good to see a built in feature to do this instead of all the hacky tricks people got up to before.
The standard mode line no longer specifies minimum widths.
The default values for the 'mode-line-position' variable and
'mode-line-format' user option no longer specify any minimum widths. If
you use a proportional font for your mode line, you may need to
customize the values of these variables to include minimum widths again.
Tab Bars and Tab Lines
Tab bars are window configurations you switch between; tab lines are like browser tabs that point to buffers in the window.
New commands 'split-tab' and 'merge-tabs'.
'split-tab' moves a specified number of windows from an existing tab to
a newly created tab. 'merge-tabs' merges all windows from two tabs into
one of these tabs, and closes the other.
New abnormal hook 'tab-bar-auto-width-functions'.
This hook allows you to control which tab-bar tabs are auto-resized.
'mouse-face' properties are now supported on the 'tab-bar'.
'tab-bar' tab buttons are now highlighted when the mouse pointer
hovers over them. You can customize the new face
'tab-bar-tab-highlight'.
New abnormal hook 'tab-bar-post-undo-close-tab-functions'.
This hook allows you to operate on a reopened tab.
This is useful when you define custom tab parameters that may need
adjustment when a tab is restored, without resorting to advice.
I do actually end up closing tab bar tabs by mistake quite often. And it has had an undo feature C-x t u to fix screwups like that for a long time now.
Tabs are now closed upon releasing the middle mouse button.
Previously, closing the tab-bar's tabs occurred upon pressing the
button.
New user option 'tab-bar-define-keys'.
This controls which key bindings tab-bar creates. Values are t, the
default, which defines all keys and is backwards compatible, 'numeric'
for tab number selection only, 'tab' for the 'TAB' and 'S-TAB' keys
only, and nil for none.
This is useful to avoid key binding conflicts, such as when folding in
outline mode using 'TAB' keys, or when a user wants to define her own
tab-bar keys without first having to remove the defaults.
New variable 'tab-bar-format-tab-help-text-function'.
This variable may be overridden with a user-provided function to
customize the help text for tabs displayed on the tab-bar. Help text is
normally shown in the echo area or via tooltips. See the variable's
docstring for the arguments passed to a help-text function.
New variable 'tab-bar-truncate'.
When non-nil, it truncates the tab bar, and therefore prevents
wrapping and resizing the tab bar to more than one line.
New user option 'tab-line-define-keys'.
When t, the default, it redefines window buffer switching keys
such as 'C-x <LEFT>' and 'C-x <RIGHT>' to tab-line specific variants
for switching tabs.
New command 'tab-line-move-tab-forward' ('C-x M-<RIGHT>').
Together with the new command 'tab-line-move-tab-backward'
('C-x M-<LEFT>'), it can be used to move the current tab
on the tab line to a different position.
New command 'tab-line-close-other-tabs'.
It is bound to the tab's context menu item "Close other tabs".
New user option 'tab-line-exclude-buffers'.
This user option controls where 'tab-line-mode' should not be enabled in
a buffer. The value must be a condition which is passed to
'buffer-match-p'.
New user option 'tab-line-close-modified-button-show'.
With this user option, if non-nil (the default), the tab close button
will change its appearance if the tab's selected buffer has been
modified.
New user option 'tab-line-tabs-window-buffers-filter-function'.
This user option controls which buffers should appear in the tab line.
By default, this is set so as to not filter out any buffers.
Aha this is useful. One problem with tab line is that it’s quite indiscriminate; it won’t show hidden buffers by default (they start with a whitespace) obviously but it’s still a bit heavyhanded. Now you can at least limit what you see.
New faces 'tab-line-active' and 'tab-line-inactive'.
These inherit from the 'tab-line' face, but the faces actually used on
the tab lines are now these two: the selected window uses
'tab-line-active', and non-selected windows use 'tab-line-inactive'.
Help
New binding 'C-h u' for 'apropos-user-option'.
IDLWAVE has moved to GNU ELPA.
The version included with Emacs is out-of-date, and is now marked as
obsolete. Use 'list-packages' to install the 'idlwave' package from GNU
ELPA instead.
New faces 'header-line-active' and 'header-line-inactive'.
These inherit from the 'header-line' face, but the faces actually used
on the header lines are now these two: the selected window uses
'header-line-active', and non-selected windows use
'header-line-inactive'.
Useful; header line is an immovable header that appears at the top of a window. It is commonly used for things like column headers in tables, as seen in M-x list-packages.
In 'customize-face', the "Font family" attribute now supports completion.
Heavenly manna indeed. I have long argued that all this complex futzing around with .Xresources, frame-setting faces and all manner of complicated ways of setting your default font is a bad habit and that M-x customize-face RET default RET is the simplest and most effective compared to the alternatives. Well, you don’t have to guess at the names of fonts any more! Emacs is finally capable of auto completing them. Excellent change.
'process-adaptive-read-buffering' is now nil by default.
Setting this variable to a non-nil value reduces performance and leads
to wrong results in some cases. We believe that it is no longer useful;
please contact us if you still need it for some reason.
Another toggle switch to maybe possibly potentially speed Emacs up a tad; it’s part of a growing list of these magic feature toggles that may or may not have adverse consequences down the road. I checked my Emacs and mine is set to nil. I do not recall why I set it to nil, nor can I remember when.
'byte-compile-cond-use-jump-table' is now obsolete.
Modified settings for an enabled theme now apply immediately.
Evaluating a 'custom-theme-set-faces' or 'custom-theme-set-variables'
call for an enabled theme causes the settings to apply immediately,
without a need to re-load the theme.
'describe-variable' now automatically says if 'setopt' is needed.
If a user option has a defcustom ':set' function, users will normally
need to set it with 'setopt' for it to take an effect. If the docstring
doesn't already mention 'setopt', the 'describe-variable' command will
now add a note about this automatically.
One of the greatest challenges in Emacs is convincing people - including yours truly - to stop using setq to bind values to global/customizable variables. Emacs’s customize system – defined as anything you can edit with M-x customize – supports edge triggers: code that runs when one of its variables change. It was once uncommon enough that nobody really had to worry; more and more things in Emacs lean into this system though.
The primary reason people use setq is that it just kinda-sorta works (notwithstanding the edge-trigger) but also because the proper way to set variables via customize’s machinery is custom-set-variables which is an obnoxious utility function that not only has a bad prefix namespace custom vs customize but also it’s just so damn long to type.
So nobody bothered to use it. Emacs 29.1 added setopt which automatically does all the heavy lifting and it’s a drop-in replacement for setq.
New user option 'eldoc-help-at-pt' to show help at point via ElDoc.
When enabled, display the 'help-at-pt-kbd-string' via ElDoc. This
setting is an alternative to 'help-at-pt-display-when-idle'.
Eldoc is Emacs’s help/document/code argument lookup system that actives when you move point around. It relies on a complex timing machinery to trigger the help. Forcing it to appear at point (even if that is nearly always your current point) is a great utility function. Now you can have eldoc without the timer: bind it to a key when you need it and off it goes.
New user option 'native-comp-async-on-battery-power'.
Customize this to nil to disable starting new asynchronous native
compilations while AC power is not connected.
Somewhere someone with a laptop more dinged-up than Zildjian cymbal lost their last 5% of battery to native comp and furiously decided to solve this problem once and for all.
New user option 'show-paren-not-in-comments-or-strings'.
If this option is non-nil, it tells 'show-paren-mode' not to highlight
parens inside comments and strings. If set to 'all', 'show-paren-mode'
will never highlight parens that are inside comments or strings. If set
to 'on-mismatch', mismatched parens inside comments and strings will not
be highlighted. If set to nil (the default), highlight parens wherever
they are.
Show paren of course is Emacs paren highlighter, though its name today is doing it a disservice as it is designed to highlight like terms like braces, string quotes or things like begin and end terms.
New user option 'view-lossage-auto-refresh'.
If this option is non-nil, the lossage buffer of 'view-lossage' will be
refreshed automatically for each new input keystroke and command
invoked.
Lossage is C-h l and it reflects the last N number of typed keys in your Emacs. With auto-refresh enabled you can simulate basic version of those “keypress overlays” people use in streaming videos. Useful for gifs too!
Change in SVG foreground color handling.
SVG images no longer have the 'fill' attribute set to the value of
':foreground' or the current text foreground color. The 'currentcolor'
CSS attribute is still set, as before.
This change should result in more consistent display of SVG images.
To use the ':foreground' or current text color ensure the 'fill' attribute
in the SVG is set to 'currentcolor', or set the image spec's ':css'
value to 'svg {fill: currentcolor;}'.
Errors signaled by 'emacsclient' connections can now enter the debugger.
If 'debug-on-error' is non-nil, errors signaled by Lisp programs
executed by 'emacsclient' connections will now enter the Lisp debugger
and show a backtrace. If 'debug-on-error' is nil, these errors will be
sent to 'emacsclient', as before, and will be displayed on the terminal
from which 'emacsclient' was invoked.
Empty string arguments to emacsclient are no longer ignored.
Emacs previously discarded arguments to emacsclient of zero length, such
as in 'emacsclient --eval "(length (pop server-eval-args-left))" ""'.
These are no longer discarded.
Huh. That may have explained some weird issues I’ve run into calling evals into emacsclient over the years. I always just assumed I did something wrong!
Emacs now uses the 'setrgbf' and 'setrgbb' terminfo capabilities.
Emacs now uses 24-bit colors on terminals that support the 'setrgbf' and
'setrgbb' user-defined terminfo capabilities. These are supported by
more terminals and applications than the old capabilities, 'setf24' and
'setb24', which are now obsolete.
I’m not an expert on termcaps so I cannot say what these caps offer people, but Emacs already supports 24-bit if you did not know. In fact, you can just set the environment variable COLORTERM=truecolor to force Emacs to treat your terminal as 24-bit capable.
New user option 'xterm-update-cursor' to update cursor display on TTYs.
When enabled, Emacs sends Xterm escape sequences on Xterm-compatible
terminals to update the cursor's appearance. Emacs can update the
cursor's shape and color. For example, if you use a purple bar cursor
on graphical displays then when this option is enabled Emacs will use a
purple bar cursor on compatible terminals as well. See the Info node
"(emacs) Cursor Display" for more information.
Neat. The highlight of course being that Emacs has multiple cursor styles. See M-x customize-option cursor-type.
New command 'copy-theme-options'.
You can use this command to copy options from a theme into your user
configuration.
New user option 'multiple-terminals-merge-keyboards'.
Customizing this option to non-nil disables entering single-keyboard
mode in most cases in which Emacs would by default enter that mode.
This can make things work better for some cases of X forwarding; see the
Info node "(emacs) Multiple Displays".
Emacs now comes with Org v9.8.
See the file "etc/ORG-NEWS" for user-visible changes in Org.
New user option 'compilation-search-extra-path'.
compile.el will now use paths specified in both
'compilation-search-extra-path' and 'compilation-search-path' when
searching. 'compilation-search-extra-path' is consulted first. One
possible use case for this option is to add new search paths on a
per-project basis with directory-local variables.
Editing Changes in Emacs 31.1
Commands for keyboard translation.
'key-translate' is now interactive. It prompts for a key to translate
from, and another key to translate to, and sets 'keyboard-translate-table'.
The new command 'key-translate-remove' prompts for a key/translation
pair, with 'completing-read', and removes the translation from the
translation table.
My article on Mastering Key Bindings in Emacs is a good place to start on key bindings.
But it is not a good article to understand keyboard translation. Even I am not crazy enough to try to write an article that explains that. I spent nearly a full day trying to trace a weird keyboard translation issue in Combobulate that only manifests in some terminals with some key bindings and only in Combobulate’s complicated “carousel interface”.
The translation system – and how it plugs into your OS, tty, etc. – and trying to fully understand it will make you go crazy.
Internationalization
Emacs now supports Unicode Standard version 17.0.
New input method 'greek-polytonic'.
This input method has support for polytonic and archaic Greek
characters.
New language environment and input method for Tifinagh.
The Tifinagh script is used to write the Berber languages.
New input methods for Northern Iroquoian languages.
Input methods are now implemented for Haudenosaunee languages in the
Northern Iroquoian language family: 'mohawk-postfix' (Mohawk
[Kanien’kéha / Kanyen’kéha / Onkwehonwehnéha]), 'oneida-postfix' (Oneida
[Onʌyote’a·ká· / Onyota’a:ká: / Ukwehuwehnéha]), 'cayuga-postfix'
(Cayuga [Gayogo̱ho:nǫhnéha:ˀ]), 'onondaga-postfix' (Onondaga
[Onųdaʔgegáʔ]), 'seneca-postfix' (Seneca [Onödowá’ga:’]), and
'tuscarora-postfix' (Tuscarora [Skarù·ręʔ]). Additionally, there is a
general-purpose 'haudenosaunee-postfix' input method to facilitate
writing in the orthographies of the six languages simultaneously.
New input methods for languages based on Burmese.
These include: Burmese, Burmese (visual order), Shan, and Mon.
New language environment and input methods for Syriac languages.
A new language environment for languages that use the Syriac script:
Classical Syriac, Aramaic, and others. There are two new input methods
for these languages: Syriac and Syriac (phonetic).
'visual-wrap-prefix-mode' now supports variable-pitch fonts.
When using 'visual-wrap-prefix-mode' in buffers with variable-pitch
fonts, the wrapped text will now be lined up correctly so that it is
exactly below the text after the prefix on the first line.
Visual wrap prefix mode, not to be confused with truncating long lines (M-x toggle-truncate-lines) or visual line mode (M-x visual-line-mode) deals with text that overflow one line and how it is wrapped. I’m not going to get into which one does what; try them out in turn and see which one works best.
New commands 'unix-word-rubout' and 'unix-filename-rubout'.
Unix-words are words separated by whitespace regardless of the buffer's
syntax table. In a Unix terminal or shell, 'C-w' kills by Unix-word.
The new commands 'unix-word-rubout' and 'unix-filename-rubout' allow
you to bind keys to operate more similarly to such a terminal.
Emacs having it all, you’d think – especially given its roots – it would already a panoply of methods for doing this.
Honestly even if you’re a die-hard fan of this method of killing I would unlearn that habit. Emacs’s combined system of moving-editing-killing by word and so forth is far superior.
New user option 'kill-region-dwim'.
This option, if non-nil, modifies the fall-back behavior of
'kill-region' ('C-w') if no region is active, and will kill the last
word instead of raising an error. If you have disabled Transient Mark
mode you might prefer to bind 'unix-word-rubout' to a key instead.
No see this is not the right way forward. C-w and M-w absent a region should kill the current line and copy it respectively. That is a far more sensible approach than fall back to dumb non-TMM behavior as it does pre-Emacs 31.
Here is the code I stole from Emacswiki 20+ years ago to do exactly this. One of my favorite Emacs life hacks:
(defadvice kill-ring-save (before slick-copy activate compile)
"When called interactively with no active region, copy a single line instead."
(interactive
(if mark-active (list (region-beginning) (region-end))
(list (line-beginning-position)
(line-beginning-position 2)))))
(defadvice kill-region (before slick-cut activate compile)
"When called interactively with no active region, kill a single line instead."
(interactive
(if mark-active (list (region-beginning) (region-end))
(list (line-beginning-position)
(line-beginning-position 2)))))
New user option 'delete-pair-push-mark'.
This option, if non-nil, makes 'delete-pair' push a mark at the end of
the region enclosed by the deleted delimiters. This makes it easy to
act on that region. For example, you can highlight it using 'C-x C-x'.
Now this is useful. M-x delete-pair (typically not bound to anything) is a long line of helpful editing commands that, alongside things like M-x raise-sexp do not get their time in the sun as they are unbound by default.
One common problem with deleting a little bit here and a little bit over there is exactly that Emacs does not make it easy to capture the extent over the change that took place. Pushing a mark (Emacs’s little point beacon system) is an obvious choice here.
Electric Pair mode
Electric Pair mode can now pair multiple delimiters at once.
You can now insert or wrap text with multiple sets of parentheses and
other matching delimiters at once with Electric Pair mode, by providing
a prefix argument when inserting one of the delimiters.
Neat but I will never remember this. I do not subscribe to the school of “think before you type” where you count your steps and then use the right numeric argument.
Electric Pair mode now supports multi-character paired delimiters.
'electric-pair-pairs' and 'electric-pair-text-pairs' now allow using
strings for multi-character paired delimiters.
To use this, add a list to both electric pair user options: '("/*" . "*/")'.
You can also specify that an extra space should be inserted after the
first string, like this: '("/*" " */" t)'.
Electric pair is a god-send in that it is a million times better than the hacky skeleton template system most of us lugged around before it became standard in Emacs a long time ago. But once again this is the sort of functionality you’d expect it could already do out of the box. Emacs’s own core is written in C where /* */ is used all the time for comments!
New user option 'electric-indent-actions'.
This user option specifies a list of actions to reindent. The possible
elements for this list are: 'yank' to reindent the yanked text, and
'before-save' to indent the whole buffer before saving it.
As always, how well this works in whitespace-sensitive languages remains to be seen. I know from experience how difficult it is to corral the indentation engines into handling this well; so for Python and such like it really can’t do much more than fixed indentation.
You can now use 'M-~' during 'C-x s' ('save-some-buffers').
Typing 'M-~' while saving some buffers means not to save the buffer and
also to mark it as unmodified. This is an alternative way to mark a
buffer as unmodified which doesn't require switching to that buffer.
M-~ generally speaking is a key binding for the “is this buffer modified in Emacs” flag. Most people do not know about this obscure command.
New minor mode 'delete-selection-local-mode'.
This mode sets 'delete-selection-mode' buffer-locally. This can
be useful for enabling or disabling the features of 'delete-selection-mode'
based on the state of the buffer, such as for the different states of
modal editing packages.
Delete selection mode is how most editors work: you select text, and if you start typing, it is deleted and replaced with what you just typed. In Emacs, you have to enable a mode to get this functionality.
New user option 'exchange-point-and-mark-highlight-region'.
When set to nil, this modifies 'exchange-point-and-mark' so that it doesn't
activate the mark if it is not already active.
The default value is t, which retains the old behavior.
This variable has no effect when Transient Mark mode is off.
I have been cargo culting an advice for this exact misbehavior around for the better part of 15 years. See Fixing the mark commands in transient mark mode.
C-x C-x is another hidden gem in Emacs. Emacs has point (your cursor) and mark (a beacon somewhere in your buffer) and back in the good old days Emacs did not highlight text selections by default. You had to slum it with no visual aid at all: all you had was your mark and point. Sounds bad, but… actually it’s not that big a deal. You generally know where you started your marking and it runs to your point.
Transient-mark-mode (obviously enabled by default… nowadays…) made it so you can see your region selection. However… it did break some useful features in weird ways. When you do M-< and such to move to the beginning or end of a buffer or C-s to start isearch Emacs will set the mark, meaning it effectively sets the start of where a region “is”.
Power users would pick a spot, search or jump or whatever to where they needed to go, and execute a “region” command that would work from where ever their point landed, say the match they picked in C-s for example, all the way back from where they were when they first called C-s. Bam — that was how you acted on a region.
So C-x C-x had really, really important purpose back then: you could swap between the mark and point by exchanging their positions. Great if you just wanted to double check the region you were going to act on; or maybe toggle between where you were/are.
So when you then execute a command (like kill-region) Emacs’s code would – slavishly, laboriously, I might add – always ensure the point and mark were the right way ’round internally, and then just act on that range.
Add highlighting into the mix and now you have a dumb rectangle that follows you along everywhere because C-x C-x would ALSO activate your region marker (C-SPC). So dumb, because it screws up keyboard macros and all sorts. Bleh.
So 15 years ago I made it not do that. And you should, too.
You can now use 'M-s t' to swap FROM and TO during 'query-replace'.
Likewise during 'query-replace-regexp'. The original binding of 'M-s'
('next-matching-history-element') is now available on 'M-s M-s' or 'M-s
s' for query replace minibuffer input.
Hah. Neat. A few versions ago they made it so various query replace functions emit a special -> sigil to indicate from/to. You could edit the whole string and move stuff around, and now they’ve just added a nice shortcut to make it even easier.
New commands for filling text using semantic linefeeds.
The new command 'fill-paragraph-semlf' fills a paragraph of text using
"semantic linefeeds", where a newline is inserted after every sentence.
The new command 'fill-region-as-paragraph-semlf' fills a region of text
using semantic linefeeds, as if the region were a single paragraph. You
can set the variable 'fill-region-as-paragraph-function' to the value
'fill-region-as-paragraph-semlf' to make commands like 'fill-paragraph'
and 'fill-region' fill text using semantic linefeeds.
Temporary files are named differently when 'file-precious-flag' is set.
When the user option 'file-precious-flag' is set to a non-nil value,
Emacs now names the temporary file it creates while saving buffers using
the original file name with ".tmp" appended. Thus, if saving the buffer
fails for some reason, and the temporary file is not renamed back to the
original file's name, and you can easily identify which file's saving
failed.
'C-u C-x .' clears the fill prefix.
You can now use 'C-u C-x .' to clear the fill prefix, similarly to how
you could already use 'C-u C-x C-n' to clear the goal column.
Fill prefix C-x . looks at where your point is on a line and designates everything from point to the beginning of the line as the fill prefix. When you type M-q on a long paragraph it’ll reflow it and insert the fill prefix for each new line. Use cases include prefixing email paragraphs with > or what have you.
Now you can reset it without having to move point to the bol.
New prefix argument for 'C-/' in Dired and Proced modes.
The Dired and Proced major modes bind mode-specific undo commands to the
same keys to which 'undo' is globally bound, 'C-/', 'C-_' and 'C-x u'.
These commands did not previously accept a prefix argument.
Now a numeric prefix argument specifies a repeat count, just like it
already did for 'undo'.
New minor mode 'center-line-mode'.
This mode keeps modified lines centered horizontally according to the
value of 'fill-column', by calling 'center-line' on each non-empty line
of the modified region.
New command 'unfill-paragraph'.
This is the inverse of 'M-q' ('fill-paragraph').
I am pretty sure org mode or something has had this for millennia buried in its codebase somewhere. But yeah, nice I guess.
Changes in Specialized Modes and Packages in Emacs 31.1
Project
Project is Emacs’s latest project management suite in a long line of project suites that ship with Emacs already. It’s nice, you should use it.
New command 'project-root-find-file'.
It is equivalent to running 'project-any-command' with 'find-file'.
New command 'project-customize-dirlocals'.
It is equivalent to running 'project-any-command' with
'customize-dirlocals'.
Improved prompt for 'project-switch-project'.
The prompt now displays the project on which to invoke a command.
'project-prompter' values may be called with up to three arguments.
These allow callers of the value of 'project-prompter' to specify a
prompt string; prompt the user to choose between a subset of all the
known projects; and disallow returning arbitrary directories.
See the docstring of 'project-prompter' for a full specification of
these new optional arguments.
'project-current' has a new optional argument, MAYBE-PROMPT.
If 'project-current' is called with this argument non-nil, then it is
passed to the 'project-prompter' to use as a prompt string.
Callers can use this to indicate the reason for which or context in
which Emacs should ask the user to select a project.
New command 'project-find-matching-buffer'.
It can be used when switching between projects with similar file trees
(such as Git worktrees of the same repository). It supports being
invoked standalone or from the 'project-switch-commands' dispatch menu.
See also the 'C-x v w w' ('vc-switch-working-tree') command, below.
That is a nice bit of symmetry. I usually switch between worktrees in magit with % g, but I am happy to see project gaining some form of generic support for this concept.
New variable 'project-find-matching-buffer-function'.
Major modes can set this to major mode-specific functions to control how
'project-find-matching-buffer' finds matching buffers.
New user option 'project-list-exclude'.
This user option describes projects that should always be skipped by
'project-remember-project'.
New user option 'project-prune-zombie-projects'.
This user option controls the automatic deletion of projects from
'project-list-file', when prompting for a project, that cannot be
accessed. The value must be an alist where each element is of the
form:
(WHEN . PREDICATE)
where WHEN specifies where the deletion will be performed, and PREDICATE
is a function which takes one argument, and must return non-nil if the
project should be removed.
New command 'project-save-some-buffers' bound to 'C-x p C-x s'.
This is like 'C-x s', but only for this project's buffers.
'project-remember-project' is now interactive.
'project-shell' and 'project-eshell' support numeric prefix buffer naming.
They now accept numeric prefix arguments to select or create numbered
shell sessions. For example, 'C-2 C-x p s' switches to or creates a
buffer named "*name-of-project-shell<2>*". By comparison, a plain
universal argument as in 'C-u C-x p s' always creates a new session.
'project-switch-to-buffer' re-uniquifies buffer names while prompting.
When 'uniquify-buffer-name-style' is non-nil, 'project-switch-to-buffer'
changes the buffer names to only make them unique within the given
project, during completion. That makes some items shorter.
'project-switch-to-buffer' uses 'project-buffer' as completion category.
The category defaults are the same as for 'buffer', but any user
customizations need to be re-added.
'project-mode-line' can now show the project name only for local files.
If the value of 'project-mode-line' is 'non-remote', project name and
the Project menu will be shown on the mode line only for projects with
local files.
One common source of performance problems in people’s riced Emacs configs is the mode line, believe it or not. It gets re-rendered more often than you think, and a lot of people cram expensive junk into it that require a file system round-trip. Fine when you’re just looking at stuff on your macbook. But over TRAMP? It’ll kill your performance.
The VC-aware project backend caches the current project and its name.
The duration for which the values are cached depends on whether it is
called from a 'non-essential' context, and is determined by the variables
'project-vc-cache-timeout' and 'project-vc-non-essential-cache-timeout'.
Network Security Manager (NSM)
NSM warns about TLS 1.1 by default.
It has been deprecated by RFC 8996, published in 2021.
NSM warns about DHE and RSA key exchange by default.
Emacs now warns about ephemeral Diffie-Hellman key exchange, and static
RSA key exchange, also when 'network-security-level' is customized to
its default 'medium' value.
Etags
Ctags, Etags, etc. are all a family of source code indexers that pull out semantically important stuff like function names and their precise location
New command-line options for handling unrecognized programming languages.
The new command-line option '--no-fallback-lang' disables attempts to
parse as Fortran or C/C++ files whose programming language 'etags' could
not determine. This allows avoiding false positives and reduces the
time required to scan directories with many such files. Another new
option '--no-empty-file-entries' disables generation of file entries in
tags tables for files in which no tags were found.
Delete Selection mode
New face 'delete-selection-replacement' for the replacement text.
This comes with a change to how we track what is considered "the
replacement text", which should be more robust, and is made more clear
by the highlighting.
Editorconfig
'editorconfig-apply' is declared obsolete.
You can now use 'editorconfig-display-current-properties' without having
to call 'editorconfig-apply'.
Auth Source
Auth source is Emacs’s declarative secret store wrapper. I’ve written about it: Keeping Secrets in Emacs with GnuPG and Auth Sources
Non-existing or empty files in 'auth-sources' are ignored.
File-based data stores are ignored in 'auth-sources' if the underlying
data file does not exist. This is relevant if a new secret is stored in
such a file; the first usable entry of 'auth-sources' is selected as the
target file. If you want files that do not exist to also be selected,
customize the user option 'auth-source-ignore-non-existing-file' to nil.
'auth-sources' set to nil means use only the password cache.
Autoinsert
Autoinsert – not to be confused with Skeletons, Abbrev, Tempo, etc. – is used to insert text templates when you create new files that match certain file patterns.
New condition for 'auto-insert-alist'.
'auto-insert-alist' can now contain predicates taking no argument as
conditions. These types of conditions should be declared with
'(predicate FUNCTION)'. This allows triggering 'auto-insert' with
finer-grained control.
Register
Registers are ephemeral stores of text snippets, window/frame configurations, point locations and much more. They’re designed for fast keyboard access and I use them all the time, especially with keyboard macros.
New commands 'buffer-to-register' and 'file-to-register'.
These allow users to interactively store files and buffers in registers.
Killed buffers stored in a register using 'buffer-to-register' are
automatically converted to a file-query value if the buffer was visiting
a file.
So a bit like bookmarks I guess, which are permanent stores of references to files, info manual locations and much more.
The "*Register Preview*" buffer shows only suitable registers.
That was already the case for the "fancy" UI but is now also true in
the default UI you get, i.e., when 'register-use-preview' is 'traditional'.
The "*Register Preview*" buffer shows sorted items.
Tree-sitter
Tree-sitter is a fancy parsing suite for structured text like code, markdown and so on. I have written an ungodly amount about tree-sitter and also code that interacts with tree-sitter.
See How to Get Started with Tree-Sitter, Combobulate: Structured Movement and Editing with Tree-Sitter, etc. etc. etc.
New user option 'treesit-enabled-modes'.
You can customize it either to t to enable all available
tree-sitter-based modes, or to select a list of tree-sitter-based modes
to enable. Depending on your customization, it modifies the variable
'major-mode-remap-alist' from the corresponding variable
'treesit-major-mode-remap-alist' prepared by tree-sitter-based mode
packages.
``