Атомарные группы изменений
В терминологии баз данных атомарное изменение — это неделимое изменение: оно может быть выполнено целиком или не выполнено вовсе, но не может быть выполнено частично. Программа на Lisp может внести ряд изменений в один или несколько буферов как атомарную группу изменений, то есть весь ряд изменений будет внесён в соответствующие буферы либо, в случае ошибки, не будет внесено ни одного изменения.
Чтобы сделать это для одного буфера — того, который уже является текущим, — просто оберните код, вносящий изменения, вызовом atomic-change-group, как показано ниже:
(atomic-change-group (insert foo) (delete-region x y))
Если внутри тела atomic-change-group возникает ошибка (или происходит другой нелокальный выход), все изменения, внесённые в этот буфер во время выполнения тела, отменяются. Такая группа изменений не влияет на другие буферы — любые изменения в них сохраняются.
Если вам нужно что-то более сложное, например объединить изменения в разных буферах в одну атомарную группу, необходимо напрямую вызвать низкоуровневые функции, которые использует atomic-change-group.
- Функция: prepare-change-group &optional buffer
Эта функция создаёт группу изменений для буфера buffer, по умолчанию — текущего буфера. Она возвращает дескриптор, представляющий группу изменений. Этот дескриптор необходимо использовать для активации группы изменений, а затем для её завершения.
Чтобы использовать группу изменений, её необходимо активировать. Это нужно сделать до внесения любых изменений в текст buffer.
- Функция: activate-change-group handle
Эта функция активирует группу изменений, обозначенную handle.
После активации группы изменений все внесённые в этот буфер изменения становятся её частью. Когда вы внесёте в буфер все нужные изменения, группу необходимо завершить. Это можно сделать двумя способами: принять (и зафиксировать) все изменения или отменить их.
- Функция: accept-change-group handle
Эта функция принимает все изменения в группе изменений, указанной в handle, и фиксирует их.
- Функция: cancel-change-group handle
Эта функция отменяет все изменения в группе изменений, указанной в handle, и выполняет их откат.
Можно сделать так, чтобы некоторые или все изменения в группе изменений считались единым целым для команд undo (см. Отмена изменений), используя undo-amalgamate-change-group.
- Функция: undo-amalgamate-change-group
Объединяет все изменения, внесённые в группу изменений начиная с состояния, обозначенного handle. Эта функция удаляет все границы отмены между записями изменений в списке отмены, начиная с состояния, заданного handle. Обычно handle — это дескриптор, возвращённый
prepare-change-group; в этом случае все изменения с начала группы объединяются в одну единицу отмены.
В вашем коде следует использовать unwind-protect, чтобы гарантировать, что группа всегда будет завершена. Вызов activate-change-group должен находиться внутри unwind-protect на случай, если пользователь нажмёт C-g сразу после его выполнения. (Это одна из причин, по которой prepare-change-group и activate-change-group являются отдельными функциями: обычно prepare-change-group вызывается до начала этого unwind-protect.) После завершения группы больше не используйте дескриптор — в частности, не пытайтесь завершить одну и ту же группу дважды.
Чтобы создать группу изменений для нескольких буферов, вызовите prepare-change-group для каждого буфера, который нужно включить в группу, а затем используйте nconc, чтобы объединить возвращённые значения, как показано ниже:
(nconc (prepare-change-group buffer-1)
(prepare-change-group buffer-2))
Затем можно активировать группу изменений для нескольких буферов одним вызовом activate-change-group и завершить её одним вызовом accept-change-group или cancel-change-group.
Вложенное использование нескольких групп изменений для одного буфера работает так, как и ожидается. Невложенное использование групп изменений для одного буфера приведёт Emacs в замешательство, поэтому не допускайте этого: первая группа изменений, начатая для любого буфера, должна быть последней завершённой группой.
Emacs отслеживает группы изменений, исходя из предположения, что, переходя по каждому cdr в buffer-undo-list, он в конце концов достигнет cons, установленного на момент вызова prepare-change-group.
Если buffer-undo-list больше не содержит этот cons, Emacs потеряет сведения обо всех группах изменений, и при отмене группы изменений возникнет ошибка. Чтобы этого избежать, пока активна группа изменений, не вызывайте функции, способные подобным образом изменять список отмены; в частности, не вызывайте команды «объединения», такие как delete-char, которые вызывают undo-auto-amalgamate.
Copyright © 1990-1996, 1998-2026 Free Software Foundation, Inc.
Licensed under the GNU GPL license.
https://www.gnu.org/software/emacs/manual/html_node/elisp/Atomic-Changes.html