
Emacs 31.1 наконец вышел. В отличие от прежних версий, в этом релизе нет одной большой знаковой фичи. Новый сборщик мусора, судя по всему, планировался для включения именно в 31.1, но его отложили до версии 32 — тема интересная и достойна отдельного разбора в будущем.
Некоторые из наиболее заметных изменений в Emacs 31.1 — небольшие, но приятные правки качества жизни, а также одно устаревание, которое знаменует конец целой эпохи.
Спор вокруг unexec/pdumper и его завершение
Emacs — не совсем обычное приложение. При компиляции и линковке получается temacs — сердце Emacs, но без большей части библиотек, которые обычно идут вместе с редактором. Это голый Emacs, состоящий из C-ядра и интерпретатора; сам по себе он мало на что годен.
Чтобы получить привычный бинарник Emacs, нужно запустить temacs и заставить его загрузить стандартную библиотеку в память. Это медленно: требуется обработать огромный объём elisp-кода и служебной логики. Запуск таким способом мог занимать несколько минут и заметное количество CPU и RAM — что совершенно неприемлемо.
Эта проблема преследовала Emacs десятилетиями. Сегодня она не критична, но в прошлом могла положить на лопатки домашние компьютеры или многопользовательские системы, если несколько энтузиастов одновременно запускали Emacs утром.
Решение проблемы: загрузить всё один раз, а затем буквально сбросить сегменты памяти Emacs (text/data/bss и так далее) в новый бинарник. После этого не нужно каждый раз заново поднимать всё состояние elisp. Технически это выглядит как борцовский приём: заваливаешь тяжеловесный Emacs, укладываешь его в новый бинарник — и всё уже готово к работе.
Довольно эффектный ход.
Но чтобы этот трюк работал, Emacs зависел от ряда специфичных функций glibc. После пары десятилетий мириться с подобным поведением команда glibc решила прекратить это, и Emacs пришлось искать другой путь.
Дэниел Коласционе разработал куда более удачное решение, хотя не всем оно понравилось. Суть его — стандартизированная сериализация внутренних структур Emacs, которая уже не является прямым дампом структур памяти один в один.
Portable dumper остаётся дефолтным механизмом уже несколько лет. Его впервые представили около десяти лет назад, и в духе многолетней традиции обратной совместимости Emacs старый unexec-дампер держали про запас — по сути, ради одного-двух пользователей, которые считали идею portable dumper сомнительной или неработоспособной.
Теперь он окончательно исчез. Конец эпохи.
Директория User Lisp
Классическая проблема: делаешь git clone или скачиваешь пакет для Emacs — и хочешь, чтобы он заработал. Но как именно? Задача не такая уж тривиальная: существует немало конкурирующих способов это сделать. Самый простой — сказать пользователям положить пакет в user-lisp/ внутри каталога .emacs.d, и Emacs сам разберётся с загрузкой и настройкой autoload (чтобы нужные команды появлялись в M-x).
Минибуфер и завершения
В Emacs 30.1 появился completion-preview-mode — встроенная система «всплывающего окна», отдалённо напоминающая Company и Corfu, но более соответствующая собственной философии Emacs: она использует окно *Completions* вместо плавающего дочернего фрейма, как это делают Company и подобные.
Emacs 31.1 развивает эту идею, добавляя целый набор настраиваемых опций для тех, кто хочет полностью перейти на нативный способ работы с завершениями.
Вращение раскладок окон
M-x window-layout-rotate-clockwise (смотрите C-x w C-h для полного списка новых опций) и подобные команды вращают раскладку окон. Ещё одна маленькая победа в плане интерфейса.
Обмен point и mark без активации региона
Отдельная тема (подробно разобранная в книге) — насколько неуклюже transient-mark-mode накинут поверх множества команд Emacs, «затрагивающих регион», таких как kill-region (C-w), как универсальное решение на все случаи жизни.
C-x C-x, обменивающий point и mark местами, заодно активирует регион — независимо от того, нужно это или нет. Об этой проблеме и способе её решения когда-то была написана статья Fixing the mark commands in transient mark mode. Теперь появилась встроенная опция отключить такое поведение — приятно.
Tree-sitter теперь сам предлагает установить грамматики
Два барьера мешают более широкому распространению tree-sitter в Emacs:
- TS требует специального major mode для работы, и часто такой мод — довольно скудная переработка оригинала.
- Установка грамматик, особенно на Windows, — настоящая головная боль: нужно не только попасть в точную ABI-версию самой библиотеки tree-sitter, но и подобрать точную версию каждой языковой грамматики, иначе всё разваливается.
Первая проблема пока остаётся, а вот вторая теперь в основном решена. Emacs наконец может сам предложить установить нужную языковую грамматику для известных ему TS-модов.
Теперь нет оправданий не попробовать Combobulate: структурное перемещение и редактирование с tree-sitter.
И многое другое
Множество мелких доработок и правок.
Изменения установки в 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.
Как уже говорилось во вступлении, это действительно конец эпохи.
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 "$@"'.
Если вы используете TAGS, стоит проверить командой where, что установлена свежая версия. (Если не знаете, используете ли вы TAGS, — значит, не используете.)
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'.
Теперь Emacs можно попросить установить systemd-сервис для запуска сервера Emacs таким способом. Рекомендуется так и делать.
Изменения запуска в 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.
Мало кто знает, что поддержку мыши в терминальном Emacs добавили ещё много лет назад, но по умолчанию она была выключена — терминалы сильно различались по возможностям, и это было разумной осторожностью. Теперь всё работает так, как и должно: меню кликабельны и так далее. Хорошее改进.
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'.
Если вы работаете на однопользовательской системе вроде ноутбука или домашнего компьютера, это вряд ли имеет для вас значение.
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.
Очень полезная вещь. Годами приходилось копировать одни и те же сниппеты кода для загрузки директорий со своими файлами — да, use-package помогает, но всё равно оставалось много ручной возни. Давно пора!
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.
Не самая приятная новость. Привычка Emacs сообщать о каждой мелкой запинке в случайном пакете теперь будет доставать даже при запуске в режиме демона. Проклятая фича. Никого это не волнует — если бы это было важно, было бы ошибкой.
Изменения в 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.
Это глобальное значение для всего Emacs, не настройка face, поэтому через M-x customize-face его не изменить. Задавайте через setopt или через настройку 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.
Приятное изменение для пользователей терминала. Фреймы в терминале работают не так, как в GUI — они больше похожи на «окна» tmux/screen. Здесь дочерние фреймы — это просто встроенные всплывающие окна, как в 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.
Важно понимать: речь не о самих faces, а о переменных, названных так же, как faces. Да, это сбивает с толку. В Emacs есть faces вроде font-lock-string-face, которые вы, вероятно, уже настраивали. Но есть и переменные с такими же именами. Устаревают именно переменные.
Если faces настраивались через M-x customize-face (а стоит делать именно так), беспокоиться не о чем.
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.
Оказывается, у этих команд не было собственной истории — теперь появилась. Полезно знать, хотя вряд ли сильно повлияет на повседневную работу.
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.
Вряд ли возникнет необходимость это настраивать.
'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'.
Минибуфер и завершения
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.
Это идёт рука об руку с изменениями в Emacs 30.1, которые сделали систему завершений минибуфера немного больше похожей на традиционные company/corfu-стайл автодополнители.
Эти новые возможности оцениваются положительно, но стоит предупредить: чтобы они действительно не мешали работе, потребуется изрядная настройка.
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.
Ещё одна небольшая правка стиля завершения, возвращающая ему поведение, которое когда-то у него уже было. В Emacs разнообразный набор стилей завершения, и дефолтный набор менялся не раз за годы — иногда к неудовольствию тех, кто привык к особенностям уже отставленного стиля. Например, в completion-styles-alist есть и стиль emacs21, и emacs22. Подробнее — в статье Understanding Minibuffer Completion.
'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'.
Довольно узкоспециальная штука. completion-styles — это, по сути, список того, как Emacs должен сопоставлять варианты в завершителе минибуфера. Теперь можно сделать так, чтобы initials игнорировал регистр, а substring — нет.
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.
Это точно стоит настроить, если планируется активно пользоваться окном Completions для завершения внутри буфера. Навигация по табличной структуре завершений всегда казалась немного странной и отталкивающей — пространство используется хорошо, но плоский список подходящих вариантов гораздо проще воспринимать.
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.
Довольно редкая функция. С её помощью можно «переключать выбор» нескольких вариантов прямо из минибуфера — мало что этим пользуется, если честно. Пользовательский опыт здесь оставляет желать лучшего, независимо от завершителя. Helm — один из немногих инструментов, где это реализовано хорошо.
Практический пример множественного выбора — в статье 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.
Ещё одна вещь, которую захочется настроить. Может понадобиться, чтобы определённые команды перемещения — например, из paredit или combobulate — не вызывали окно завершения.
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.
Хорошее решение, и приятно, что оно включено по умолчанию: без явного состояния «выбрано/не выбрано» легко запутаться.
'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.
Когда-то разработчики поменяли способ ответа на подсказки «yes or no» в Emacs, сделав его больше похожим на обычный минибуфер — и в своё время это застало врасплох, а разобраться в причине было той ещё морокой. Стоит держать это в уме, если случится похожая ситуация.
'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-сопоставление — фича из ido-mode, и, судя по всему, это её переработанная версия для завершителя fido-mode, построенного на «новой» системе завершений минибуфера. Про IDO — статья Introduction to Ido Mode; про вторую систему — Understanding Minibuffer Completion.
Мышь
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.
Мышью в Emacs выделяют редко, но для мелких точечных задач это действительно бывает быстрее клавиатуры, если делается один раз.
'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.
Отличное дополнение. M-x context-menu-mode сам по себе относительно новая функция (появилась в Emacs 28) и по умолчанию выключена. Она добавляет контекстные меню по правому клику. Не так просто уследить за всеми местами, куда добавлялись собственные команды, а поскольку дефолт довольно скудный, многие пользователи, вероятно, просто прошли мимо.
Режим контекстного меню можно вызвать вручную (независимо от того, включён ли minor mode) командой 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.
Окна
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.
Отличное дополнение. Хотя на практике, скорее всего, будет выбрано одно направление — по часовой стрелке или наоборот — и привязано к удобной клавише, а дальше придётся просто нажимать её несколько раз. Такая операция нужна нечасто. Любопытно, впрочем, как устроена реализация: судя по всему, она обходит все узлы дерева (раскладка окон в Emacs представлена как древовидная структура) — можно посмотреть внутреннее представление командой M-: (window-tree).
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.
Вращать окна, но не следовать за ними? На любителя.
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.
Оставить этот параметр в nil разумно: dedicated-окна закреплены неспроста, и вращать их обычно не входит в планы — хотя, конечно, бывают и особые сценарии работы.
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 перебирает окна, как многие знают. Но окно можно пометить (см. Demystifying Emacs's Window Manager) как no-other-window, исключив его из этой команды. Windmove, в свою очередь, позволяет перемещаться между окнами стрелками.
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 всегда были странные, слабо связанные отношения между буферами и окнами, что подтвердит каждый, кто пытался укротить оконный менеджер (см. упомянутую ранее статью). Это похоже на очередную заплатку поверх практически неразрешимой проблемы: как удержать две легко взаимозаменяемые сущности от манипуляций, которых пользователь или пакет не хотел? Похоже, ответ — «ещё больше хуков»…
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.
И снова, как и выше — все эти решения похожи на пластырь, наложенный на неразрешимую в принципе проблему. Если позволить окну показывать что угодно, а буферу — прыгать куда угодно (механически или по прихоти пользователя), то как удержать всё под контролем ради IDE-подобного поведения?
Сама идея этих опций нравится, хотя вряд ли ими будут активно пользоваться — даже в пакетах.
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)'.
Ничего критичного.
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.
Хорошая новость для тех, кого раздражала хаотичность разбиения окон. Теперь есть хоть какой-то контроль над направлением. Стоит взять на заметку и настроить эту опцию, если разбиение упорно происходит не в ту сторону.
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.
Возражений нет.
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.
Косвенные буферы — фича для опытных пользователей. Если нужно делать разные вещи в одном и том же буфере, можно разбить окно и «указать» новое окно на уже открытый буфер, но тогда возникают неудобства вроде общего major mode и того, что курсор не всегда помнит нужное место из-за особенностей работы points и windows. Косвенный буфер указывает на базовый буфер, от которого он клонирован: текст общий, но всё остальное (например, 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.
Действительно интересная штука — но вопрос, насколько хорошо она заработает, если вызвать что-то через мудрёные диспетчеры вроде magit или org.
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'.
Больше не нужен отрицательный префиксный аргумент, чтобы двигаться назад.
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'.
Любопытно, как это соотносится с атомарными окнами — другим способом «объединения» окон. Наверняка есть существенная разница, возможно, в том, что новая функция никак не привязана к 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.
Фреймы
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.
Использование фреймов — не самая частая практика, поскольку настройка под собственный вкус обычно того не стоит, даже при использовании тайлингового WM. Но возврат к последнему просматриваемому фрейму действительно кажется странно поздним дополнением; это наверняка порадует тех, кто предпочитает подход с фреймами вместо окон.
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<number>" on text terminals.
Unlike with other frame names, an attempt to rename to "F<number>"
signals an error when a frame of that name already exists.
Как уже упоминалось, фреймы в терминальном Emacs — это, по сути, ещё один способ настройки конфигурации окон в стиле screen.
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.
Одна из старых статей на сайте была посвящена именно этому — Hiding and replacing modeline strings with clean-mode-line. Проблема существует ровно столько, сколько авторы модов сами решают, насколько «громкими» должны быть их индикаторы в строке режима.
Хорошо, что эта функция наконец встроена. Пока неясно, работает ли она вместе с :delight / :diminish в 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.
Эту функцию просят регулярно, так что хорошо видеть встроенное решение вместо всех прежних хакерских обходных путей.
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 — это раскладки окон, между которыми можно переключаться; tab lines больше похожи на вкладки браузера, указывающие на буферы внутри окна.
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.
Вкладки в tab-bar периодически закрываются случайно, и функция отмены C-x t u уже давно спасает от подобных ошибок.
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.
Полезная штука. Одна из проблем tab line в том, что она довольно неразборчива: скрытые буферы (начинающиеся с пробела) она, конечно, не показывает по умолчанию, но в целом слишком грубо фильтрует список. Теперь хотя бы можно ограничить то, что отображается.
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'.
Справка
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'.
Полезно: header line — неподвижный заголовок вверху окна, часто используемый, например, для заголовков столбцов в таблицах, как в M-x list-packages.
In 'customize-face', the "Font family" attribute now supports completion.
Долгожданное благо. Всё это сложное копание в .Xresources, faces, задающих настройки фрейма, и прочих запутанных способах задать шрифт по умолчанию — плохая привычка, и M-x customize-face RET default RET куда проще и эффективнее альтернатив. Теперь больше не нужно угадывать названия шрифтов — Emacs наконец умеет их автодополнять. Отличное изменение.
'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.
Ещё один тумблер, возможно немного ускоряющий Emacs — из растущего списка подобных «магических» переключателей, у которых со временем могут обнаружиться побочные эффекты. Проверка собственной конфигурации показала, что переменная уже стояла в nil — правда, вспомнить, когда и почему это было сделано, не удалось.
'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.
Одна из вечных проблем Emacs — убедить пользователей отказаться от setq для присвоения значений глобальным/настраиваемым переменным. Система customize (всё, что можно редактировать через M-x customize) поддерживает триггеры на изменение: код, срабатывающий при смене значения переменной. Раньше это встречалось нечасто, и никто особо не беспокоился, но со временем всё больше частей Emacs опираются именно на эту систему.
Основная причина популярности setq — он просто более-менее работает (несмотря на триггеры), а правильный способ через машинерию customize — функция custom-set-variables, у которой неудобное пространство имён (custom вместо customize) и слишком длинное имя, чтобы печатать его каждый раз.
Поэтому её никто и не использовал. В Emacs 29.1 добавили setopt, которая берёт всю тяжёлую работу на себя и служит прямой заменой 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 — система Emacs для показа справки/документации/аргументов функций, срабатывающая при перемещении курсора. Она полагается на сложную систему таймеров для запуска подсказки. Возможность вызвать справку прямо в точке курсора по требованию — отличная утилита: теперь можно получить eldoc без таймера, просто привязав его к клавише.
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.
Где-то кто-то с ноутбуком, потрёпанным больше старой тарелки Zildjian, потерял последние 5% батареи из-за native-compilation и наконец решил закрыть этот вопрос раз и навсегда.
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 — подсветчик скобок в Emacs, хотя название сегодня не совсем отражает суть: он умеет подсвечивать и парные конструкции вроде фигурных скобок, кавычек строк или пар begin/end.
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 вызывается по C-h l и показывает последние N нажатых клавиш. С включённым авто-обновлением можно получить упрощённый аналог тех «оверлеев с нажатыми клавишами», которые используют стримеры. Пригодится и для записи gif.
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.
Этим, возможно, объясняются некоторые странные проблемы при вызовах eval через emacsclient за прошедшие годы — раньше это неизменно списывалось на собственную ошибку.
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.
Судить об этих termcap-возможностях детально сложно, но 24-битный цвет в Emacs поддерживается уже давно. Более того, можно просто выставить переменную окружения COLORTERM=truecolor, чтобы заставить Emacs считать терминал 24-битным.
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.
Приятная деталь: у Emacs есть несколько стилей курсора. См. 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.
Изменения в редактировании в Emacs 31.1
Commands for keyboard translation.
'key-translate' is now interactive. It prompts for a key to translate
from, and another 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.
Статья Mastering Key Bindings in Emacs — хорошая отправная точка для изучения биндингов.
А вот для понимания клавиатурной трансляции она не подойдёт — написать статью, объясняющую именно эту тему, отваживается не каждый. Целый день ушёл на отслеживание странной проблемы с трансляцией клавиш в Combobulate, которая проявлялась только в некоторых терминалах с определёнными биндингами и только в сложном «карусельном интерфейсе» Combobulate.
Система трансляции — и то, как она встраивается в ОС, tty и прочее — способна свести с ума при попытке разобраться в ней до конца.
Интернационализация
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 — не путать с обрезкой длинных строк (M-x toggle-truncate-lines) или visual-line-mode (M-x visual-line-mode) — отвечает за то, как переносится текст, не помещающийся в одну строку. Разбирать подробно, чем они друг от друга отличаются, смысла нет — проще попробовать каждый и выбрать подходящий.
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, логично было бы ожидать, что подобный набор методов работы с текстом уже давно существует в изобилии.
Даже убеждённым сторонникам такого способа удаления стоит от него отвыкнуть: объединённая система перемещения-редактирования-удаления по словам в Emacs значительно превосходит его по возможностям.
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.
Впрочем, это тоже не совсем верный путь. C-w и M-w при отсутствии региона логичнее было бы заставить убивать/копировать текущую строку — куда более разумный подход, чем откат к тупому поведению без TMM, как это было до Emacs 31.
Ниже — код, позаимствованный с Emacswiki больше 20 лет назад, делающий именно это. Один из любимых лайфхаков для Emacs:
(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'.
Полезное дополнение. M-x delete-pair (обычно ни к чему не привязана) относится к целой серии полезных команд редактирования, которые, наравне с M-x raise-sexp, редко получают заслуженное внимание, поскольку по умолчанию не имеют горячих клавиш.
Одна из типичных проблем при точечном удалении фрагментов то тут, то там — как раз в том, что Emacs не даёт легко зафиксировать границы произошедшего изменения. Простановка mark (маленького маячка Emacs) здесь напрашивается сама собой.
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.
Удобно, но запомнить это вряд ли получится — привычки «сначала думать, потом печатать», считая шаги ради нужного числового аргумента, попросту нет.
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 — настоящее спасение по сравнению с хакерской системой шаблонов-скелетонов, которой многие пользовались до того, как этот режим стал стандартным в Emacs. Но опять же — от такой функциональности логично было бы ожидать поддержки «из коробки» с самого начала: само ядро Emacs написано на C, где /* */ постоянно используется для комментариев!
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.
Как обычно, остаётся вопрос, насколько хорошо это работает в языках, чувствительных к пробелам. По опыту известно, насколько сложно заставить движки отступов справляться с этим корректно; для Python и подобных языков реально доступен разве что фиксированный отступ.
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-~ — в целом, биндинг для флага «изменён ли этот буфер в Emacs». Большинство пользователей об этой малоизвестной команде не знает.
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 реализует привычное для большинства редакторов поведение: выделяешь текст, начинаешь печатать — он удаляется и заменяется набранным. В Emacs для этого нужно включить отдельный режим.
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.
Уже добрых 15 лет для решения именно этой проблемы использовался самописный advice. Подробности — в статье Fixing the mark commands in transient mark mode.
C-x C-x — ещё один скрытый бриллиант Emacs. В редакторе есть point (курсор) и mark (маячок где-то в буфере), и в старые добрые времена Emacs по умолчанию не подсвечивал выделение текста. Приходилось обходиться вовсе без визуальной подсказки: только mark и point. Звучит неудобно, но на деле — не так уж и страшно: обычно и так помнишь, откуда началось выделение и куда дошёл курсор.
Transient-mark-mode (само собой, включённый по умолчанию сегодня) сделал возможным видеть выделение региона. Однако он же странным образом ломал некоторые полезные приёмы. Когда выполняется M-< для перехода в начало или конец буфера, или C-s для запуска isearch, Emacs выставляет mark — то есть фактически задаёт начало региона.
Опытные пользователи выбирали точку, искали или прыгали туда, куда нужно, а затем выполняли «региональную» команду, которая действовала от текущей позиции курсора (скажем, найденного совпадения при C-s) вплоть до места, откуда изначально был вызван C-s. Именно так раньше действовали на регион.
Поэтому у C-x C-x была по-настоящему важная роль: он позволял поменять местами mark и point. Удобно, если требовалось перепроверить регион перед действием или просто переключиться между тем, где был курсор, и тем, где он сейчас.
При выполнении команды вроде kill-region код Emacs — надо признать, довольно педантично — всегда сначала расставлял point и mark в верном внутреннем порядке, а затем уже действовал на этот диапазон.
Добавьте сюда подсветку — и получится тупой прямоугольник, который таскается за вами повсюду, потому что C-x C-x ЗАОДНО активировал маркер региона (C-SPC). Крайне неудобно, поскольку ломает клавиатурные макросы и многое другое.
Именно поэтому 15 лет назад это поведение было отключено вручную. Стоит сделать то же самое и сейчас.
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.
Приятная мелочь. Несколько версий назад различные функции query-replace стали показывать специальный значок -> для обозначения «откуда/куда» — можно было редактировать всю строку и переставлять части местами, а теперь добавили удобный шорткат, делающий это ещё проще.
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 .) смотрит на позицию курсора в строке и назначает всё от начала строки до курсора префиксом заполнения. При вызове M-q на длинном абзаце текст переформатируется, и этот префикс добавляется к каждой новой строке. Практическое применение — например, оформление цитат в письмах символом >.
Теперь сбросить его можно, не перемещая курсор к началу строки.
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').
Похожая функция наверняка давно существует где-то в недрах org-mode. Но всё равно приятное дополнение.
Изменения в специализированных модах и пакетах Emacs 31.1
Project
Project — новейший пакет управления проектами в длинной череде подобных решений, идущих в комплекте с Emacs. Пакет хороший, стоит попробовать.
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.
Приятная симметрия: переключение между worktree в magit обычно делается через % g, и теперь хорошо видеть, что project получает собственную поддержку этой концепции в более общем виде.
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.
Один из частых источников тормозов в перегруженных конфигурациях Emacs, как ни странно, — строка режима. Она перерисовывается куда чаще, чем можно подумать, и многие пихают в неё дорогие вычисления, требующие обращения к файловой системе.