docs(articles): Emacs 31 article

This commit is contained in:
2026-05-02 19:47:30 +02:00
parent b60d8de739
commit cc7600e004
2 changed files with 424 additions and 51 deletions

View File

@@ -1,51 +0,0 @@
kind: pipeline
name: default
steps:
- name: build
image: silex/emacs:27-alpine
commands:
- apk add hugo git
- git submodule update --init --recursive
- mkdir blog
- emacs --script .export.el
- hugo -d blog
- name: deploy
image: appleboy/drone-scp
settings:
host:
from_secret: ssh_host
target:
from_secret: ssh_target
source: blog/*
strip_components: 1
username:
from_secret: ssh_username
password:
from_secret: ssh_password
port:
from_secret: ssh_port
when:
branch:
- master
event:
exclude:
- pull_request
- name: purge cache
image: jetrails/drone-cloudflare-caching
settings:
api_token:
from_secret: cloudflare_cache_api
zone_identifier:
from_secret: phundrak_com_zone_id
action: purge_files
list:
- https://blog.phundrak.com
when:
branch:
- master
event:
exclude:
- pull_request

View File

@@ -808,6 +808,430 @@ Happy programming!
* Emacs :@emacs:
** Emacs 31 is coming, and heres whats new! :dev:emacs:release:
:PROPERTIES:
:EXPORT_FILE_NAME: emacs-31-is-coming-heres-whats-new
:EXPORT_DATE: 2026-01-02
:EXPORT_OPTIONS: toc:2
:export_hugo_menu: :menu "main"
:END:
[[https://blog.phundrak.com/emacs-29-what-can-we-expect/][A few years ago]], I published a blog post regarding what was new in
Emacs 29 as it came close to being released. I missed the mark for
Emacs30, but now, Emacs31 is getting ready for release.
So, what can we expect for Emacs31? Everythings written in its =NEWS=
file, but here are some elements I think are important. Be warned,
although Im not as hyped as I was for Emacs29 that brought a few big
features, this article is quite a bit longer.
*** Breaking Change
**** Configuration
=site-start.el= will now load before your =early-init.el=, instead of
after it.
**** Python
=python-mode= will now default to calling =python= instead of =python3=,
though it will fall back to =python3= if =python= is not found. Most modern
systems no longer ship Python2, and =python= most likely points to
Python3. If =python= still points to Python2 on your system, you *MUST*
change the value of =python-interpreter= and =python-shell-interpreter=.
As Python2 has been EOL for five years now, its support is now
optional and disabled by default.
*** Editing
With the new option =kill-region-dwim= set to non-nil, calling
=kill-region= will now kill the last word instead of raising an error if
no region is selected.
Electric Pair mode got better: you can now set strings using multiple
characters in =electric-pair-pairs=, such as ='("r#\"" . "\"#")= to
surround a region with =r#"= and ="#=. And if you want an extra space
between your delimiters and the selected region, you can instead use
='("r#\"" "\"#" t)=. Also, providing a numerical prefix argument to
electric pair allows you to insert multiple delimiters at once. Now, I
just need mode-aware electric pairs to replace [[https://github.com/emacs-evil/evil-surround][evil-surround]].
Do you use =query-replace=? Well, you can now use =M-s t= to swap =FROM= and
=TO= during a =query-replace= or =query-replace-regexp=. And the original
=M-s= is now =M-s M-s= or =M-s s=.
And do you like always having the line youre editing to be at the
centre of your window? Activate =center-line-mode=.
Accidentally hit =M-q= (=fill-paragraph=) and you want to undo it? Or you
simply want to “unfill” your paragraph? Simply invoke =unfill-paragraph=
(which I will probably bind to =M-Q=).
*** TTY Improvements
One of my biggest gripes with Emacs in the terminal is how limited it
feels to its GUI version. Child frames, for instance, are one of TTY
Emacs limitations. Or, rather, /was/.
Starting from Emacs31, TTY Emacs will support child frames, thanks to
=tty-child-frames=. Hurray for Posframe and Corfu users among many
others!
The option =xterm-mouse-mode= is also now enabled by default in
terminals that support it, i.e. allowing Emacs to access the OS
clipboard and mouse events. This means you can now bind mouse events
to Emacs functions, but at the cost of now having to rely entirely on
Emacs to copy and paste text instead of relying on your terminal
emulator.
Also, you can now rename your TTY frames to =F<number>=, though it will
throw an error if that name is already taken.
*** Proper Support for User Lisp Directories
Emacs will natively support your =user-lisp/= directory in your Emacs
config directory (either your =$HOME/.emacs.d/= or your
=$HOME/.config/emacs/= directories) by recursively byte-compiling all of
its =.el= files and adding them to your =load-path=. It will also look for
autoloaded elements like it would for other packages, so no need to
explicitely require your =.el= files anymore!
This feature can be disabled with =(setq user-lisp-auto-scrape nil)=, or
you can change the directory =user-lisp-directory= points to if your
personal Elisp files are stored somewhere else.
Very nice, thanks Emacs devs!
*** Visual Customization and Improvements
**** Display
The new char-table =special-mirror-table= allows you to define
replacement characters for characters Emacs may have trouble
displaying. I think that, for most native English speakers, this
feature might be pretty useless, but it can be very interesting if you
deal with glyphs that are not ASCII, especially if they are part of
your writing system (Arabic, Mandarin, Cyrillic, etc…).
I, for one, am excited for this, as I use Emacs for most of my
worldbuilding projects, which include conlanging (creating languages),
and it requires me sometimes using characters Emacs has troubles
representing. I also have some glyphs in my Linux that render properly
with certain fonts that Emacs cannot render well with the font it
uses, therefore not making the config all that readable (Im looking
at you, [[https://labs.phundrak.com/phundrak/nix-config/src/commit/5514d347c754ea17dd2a3ecb40fed6a62182c7ea/users/modules/desktop/waybar.nix#L59-L71][my Waybar configuration]], which I should remove since I already
dont use Waybar any more).
On the topic of display customization, a few font-locks were deprecated:
- =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=
- =font-lock-warning-face=
They all have equivalents, you should customize them instead of these
deprecated font-locks.
**** Windows
We get some new commands for manipulating our window layouts!
- =C-x w t= and =C-x w r <left>/<right>= to rotate the window layout
- =C-x w o <left>/<right>= to rotate the windows within the current
layout
- =C-x w f <left>/<right>/<up>/<down>= to flip the layout
And now, you can also indicate to Emacs to kill buffers when their
window is closed, thanks to the =kill-buffer-quit-windows= option. But I
think Ill personally stick to =kill-buffer-and-window=, this new option
seems a bit overkill for me. Still, quite nice to have!
Some commands and functions will create new windows on their own.
Emacs current behaviour is to split below if possible, and split
right otherwise. But now, =split-window-preferred-direction= introduces
three values:
- ='longest= :: somewhat similar to the current behaviour, and the new
default value: split below if your window is taller than it is wide
(Emacs preferred direction whenever possible), split right
otherwise. But what if both options are possible? Well, now, you can
set =split-width-threshold= (now 150 instead of 160) and
=split-height-threshold= to determine the correct behaviour to follow.
- ='vertical= :: always split below
- ='horizontal= :: always split right
The new command =other-window-backward= is also finally here! Ever
wanted to go back to your initial window after =C-x o= (=other-window=)?
Just use =C-x O= to go back!
**** Frames
Ever wondered how much time youve spent in a frame, like how you can
already determine it with =window-use-time= (which I just discovered
now)? With Emacs31, you can now use the function (not command)
=frame-use-time=.
=delete-frame= now sends you to your most recently used frame, not the
first one in the list of frames. A small change, but a welcome change.
The new command =split-frame= now allows you to create a new frame and
send windows of your current frame to this new frame. The command
=merge-frames=, on the other hand, brings back a frames windows into
another before killing it. Very nice if you want to bring back a TTY
frame into another GUI frame, and /vice versa/.
Also, frames cloned with =clone-frame= (which I just discovered exists)
are now aware which frame they were cloned from, and if they were
undeleted with =undelete-frame= (how many commands will I learn exist
while writing this article?). And all frames have now a unique ID,
much easier to refer to a specific frame in your Elisp code, such as
with the new commands =select-frame-by-id= or =undelete-frame-by-id=.
**** Mode Line
The mode line can now collapse its minor modes when setting
=mode-line-collapse-minor-modes= to non-nil, useful when it becomes to
feel bloated. By default, its =nil=, so it wont change its default
behaviour. It also became much easier to customize, using
=mode-line-modes-delimiters= to change or remove the existing
delimiters. Writing new mode line themes is about to get a lot easier!
But what if you dont want to see the mode line? Well, hide it with
=mode-line-invisible-mode=, and enjoy your distraction-free Emacs!
**** Tabs
When tabs were introduced in Emacs, I didnt really see the point
initially, until I realized theyre somewhat similar to sub-frames
without actually creating new frames. Very nice if, like me, you
prefer to have a single frame despite working on several projects with
the same Emacs instance. But an issue I often encounter (might be a
skill issue on my part) is that they sometimes become quite bloated,
crossing over multiple projects, at which point I decide to create
another tab and restore one specific project to that tab, recreating
my window layout with the buffers I want. Thats a tad tedious.
Well now, you can invoke the command =split-tab= to clone your current
tab to a new one and keep your windows! And of course, it comes with
=merge-tabs=, in case youre finally done with this specific issue your
tab was for, and you want to go back to the projects general tab. And
in case you have a lot of tabs opened, =tab-bar-truncate= when set to
non-nil will now truncate your tabs list, instead of squishing them
together and avoid any ugly text wrapping.
The use-case =tab-line-mode= is, however, a bit more mysterious for me,
but I guess it makes sense when you come from editors like VSCode and
are used to see all your open files as tabs (not Emacs tabs, but more
what I expected tabs to be when they were first announced). And now,
you can use =tab-line-define-keys= and set it to =nil= to avoid
=tab-line-mode= redefine =C-x <left>/<right>= switch between the visual
tabs and go back to Emacs vanilla behaviour. You can also move your
tabs position among your tabs in =tab-line-mode= with the new commands
=tab-line-move-tab-forward= and =tab-line-move-tab-backward=, which are
bount to =C-x M-<right>/<left>=. And you can also set
=tab-line-exclude-buffers= to exclude known buffers from the tabs, such
as =*scratch*= or =i-dont-want-my-boss-to-see-this-when-he-walks-by.txt=.
In fact, you can even have even more powerful filtering using
=tab-line-tabs-window-buffers-filter-function=. And using the option
=tab-line-close-modified-button-show=, you can see the close button
visually warning you the buffer has been modified but not saved. Nice.
Something I just learned is that you can close tabs with your mouses
middle click. But what if you made a mistake, clicked on the wrong
tab, and realized your mistake before releasing the button? Until
Emacs30, thats too late. Since Emacs31, the tab will be deleted
once you release the button, so you can still move the mouse and
release the button either on the correct tab, or outside the tabs area
if you dont want to close anything.
*** Completion Improvements
The =*Completions*= buffer can now be much faster, updating as you
write, given the =eager-update= completion property is non-nil. And if
you dont like the default value of the property, you can override it
with =completion-category-overrides=. And you can force the
autocompletion to update eagerly with =(setq completion-eager-update t)=
(or any value that is non-nil, but why not just use =t=?), but that can
slow Emacs down; I turned it off on my ThinkPadX220 and its
IntelCorei5-2540M (yes, I still use it), but on for my main desktop
computer with its AMDRyzen79800X3D. I should upgrade my X220s CPU
sometime. But fortunately, the =*Completions*= buffer still got a
performance upgrade, especially when many candidates exist, though
with one caveat (see below in this chapter).
You can also now separate what the up/down keys do from the left/write
keys when in the minibuffer! If you set the
=minibuffer-visible-completions= option to ='up-down=, you can now have
the up/down keys select different suggestions in the =*Completions*=
buffer, while the left/write keys moves your cursor in the minibuffer.
Similarly, the =M-<up>= and =M-<down>= keys now allow you to select
candidates in the =*Completions*= buffer, whether your completion is in
the minibuffer on in-buffer. And in all cases, =RET= now chooses the
completion you selected.
If you want to customize how the completion candidates are displayed,
you can now use =completions-format=: set it to ='vertical=, selecting the
next candidates means selecting the one below the one currently
selected, wrapping to the net column when you reached the bottom. But
setting it to ='horizontal= will keep the old behaviour intact,
selecting the next option right of your current selection when using
=M-<down>=. But be careful, setting =completions-format= to ='vertical= will
undo the improvements the =*Completions*= buffer received. Not an option
for my ThinkPad.
By the way, your selection is now consistent even if the =*Completions*=
buffer updates! Its frustrating when you started selecting something,
but for some reason, something triggered a completions update, and now
you have to move again to what you were about to select.
*** Minibuffer Improvements
How many times have I tried to do something, only for Emacs to not do
what I wanted because the minibuffer was active but not actively
selected? Well now, =minibuffer-nonselected-mode= will warn you when you
should probably pay attention to the minibuffer, as its waiting for
your input. Especially useful when you /think/ its selected, but its
actually not.
*** Mouse Improvements
When selecting text with your mouse and invoking =context-menu-mode=,
you can now select =Send to...= to send your text selection, or even the
current file, to external applications!
*** Built-in Package Updates
**** Org Mode Updated to 9.8
You may already have Org Mode 9.8 if you dont use Emacs builtin
package, but this new version comes with some nice new features, such
as a new babel backend for C#, customizable images alignment, fixed
and better LaTeX table export, and so on.
**** Project
No need for calling =M-x project-any-command M-x find-file= any more!
You can now call =project-root-find-file= instead. And no need for =M-x
project-any-command M-x customize-dirlocals=, you can use
=project-customize-dirlocals= instead.
The new command =project-find-matching-buffer= can also be useful when
switching, for instance, git worktrees of the same repository, or
simply repositories with a similar structure. You can customize its
behaviour with =project-find-matching-buffer-function=.
You can also only save a projects files with =M-x
project-save-some-buffers= or =C-x p C-x s=, similarly to projectiles
=projectile-save-project-buffers=.
**** Tree-sitter
The new option =treesit-enabled-modes= will enable all known tree-sitter
modes by default when set to =t=, or only the tree-sitter based modes in
the list given to it, such as =(setopt treesit-enabled-modes
'(c-ts-mode nix-ts-mode uiua-ts-mode)=. It may change
=major-mode-remap-alist= based on =treesit-major-mode-remap-alist= if
needed.
The user option =treesit-auto-install-grammar= is one step to replace
[[https://github.com/renzmann/treesit-auto][treesit-auto]], with =treesit-extra-load-path= being a list of directories
where grammars are installed. If you install a grammar with
=treesit-auto-install-grammar=, it will be installed in the first
directory. =treesit-language-source-alist= now supports keywords such as
=:commit=, in case the default commit selected doesnt match what you
want (a bug you want to avoid, or which you may consider a feature).
By the way, discoverability of things to natively do with tree-sitter
has become better! Use =treesit-cycle-sexp-thing= to explore the
navigation commands you can call.
You can also use =treesit-language-remap-alist= to make Emacs language A
is language B, which would allow you to use Bs parser for A.
Especially useful if you know B is a superset of A, like Typescript is
a superset of JavaScript.
Tree-sitter also now properly supports lists and comments and allows
you to act on them!
It also now allows for better support of multiple programming
languages, such as =treesit-simple-indent-modify-rules= which unifies
across languages indentation rules,
=treesit-aggregated-simple-imenu-settings= for Imenu setup for multiple
languages, and =treesit-aggregated-outline-predicate= which indirectly
allows for =outline-minor-mode= for multiple languages. Thatll be quite
enjoyable when Ill work on Vue files, with HTML, Typescript, and LESS
code all in the same file. Speaking of indentation, keep an eye on
=treesit-simple-indent-add-rules= and
=treesit-simple-indent-override-rules=.
***** Language Specifics
Doxygen is now supported by =c-ts-mode= and =java-ts-mode= if enabling
=c-ts-mode-enable-doxygen= and =java-ts-mode-enable-doxygen= respectively.
=go-ts-mode= now has unit test
support with a few new commands like =go-ts-mode-test-function-at-point=
which does exactly what you think it does,
=php-ts-mode= had a lot of work done: it now requires =mhtml-ts-mode=
instead of =js-ts-mode=, =css-ts-mode= and =html-ts-mode= directly, and it
now benefits greatly from the multilingual improvements I talked about
earlier.
=rust-ts-mode= now fontifies number suffixes as types (like =10_u32=) when
=rust-ts-mode-fontify-number-suffix-as-type= is non-nil.
*** Eshell
Eshell also got some improvements: =eshell-clear= is now a better
behaved =eshell/clear= alternative, while =eshell-execute-file= went from
function to command.
You can also set the stderr of =eshell-command= and =eshell-execute-file=.
The syntax of Eshell also got an upgrade: the =for= command can now loop
over integer ranges, such as =1..10= (first number included, last
excluded), and you can also use =else= in =if {condition} {true-command}
else {false-command}= (=else= remains optional). You can also now chain
=else if=, as the =false-command= can be its own if/else statement.
The history search got an improvement, with the ability to search with
regular expressions with the two new =eshell-isearch-backward-regexp=
and =eshell-isearch-forward-regexp=, or =M-r= for the backward search
while =M-s= is now freed.
You can also set inter-session history off by setting
=eshell-history-isearch= to nil (the default value), which will limit
isearch to the Eshells buffer content only. If set to =t=, it will
search in the input history only, and if set to ='dwim=, it will search
in the input history only if the point is after the last prompt.
*** A Few Additional Goodies
=emacs-lisp-mode= now supports semantic highlight when
=elisp-fontify-semantically= is non-nil.
A few years back, =setopt= came into Emacs as a better alternative to
=setq= for most variables declared with =defcustom=. Well, now,
=describe-variable= will tell you if a variable should be set with
=setopt=, or if other methods is alright.
Something my ThinkPad will be thankful of, and a lot of laptops also
will be, is the new option =native-comp-async-on-battery-power=: if set
to nil, Emacs will not attempt to use the asynchronous native
compilations if your laptop is running only on its battery. The
libraries that need compilation will be a tad slower, but you wont
have to look for a power socket as soon as with Emacs30. Especially
nice for those in the Northern Hemisphere who want to enjoy the
upcoming summer! Or if youre one of the weirdos like me who enjoy the
cold more than the heat.
Something Ill really appreciate is setting
=show-paren-not-in-comments-or-strings= to stop Emacs from highlighting
parenthesis and brackets in comments or strings.
Sending empty strings to =emacsclient= is now possible! Until Emacs30,
passing an empty string was the same as not passing one it at all.
Now, Emacs will understand it!
Emacs now supports Unicode 17.0, in case you wanted to write something
with the Sidetic, TolongSiki, BeriaErfe, or TaiYo scripts. I was
prepared to make an emoji joke, but surprisingly, Unicode17 did not
add any. Speaking of scripts, Emacs now support new input methods,
such =greek-polytonic= for polytonic and archaic Greek, but also quite a
few input methods for Northern Iroquoian languages, Burmese-based
languages, and Syriac languages. My inner amateur linguist approves
immensely!
Emacs now dislikes insecure protocols: its Network Security Manager
will warn you about TLS1.1 and DHE and RSA key exchange.
** f.el v0.21.0 released! :dev:emacs:release:
:PROPERTIES:
:EXPORT_FILE_NAME: f-el-v0-21-0-released