Spec-Zone.ru › Elisp

Атомарные группы изменений

В терминологии баз данных атомарное изменение — это неделимое изменение: оно может быть выполнено целиком или не выполнено вовсе, но не может быть выполнено частично. Программа на 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API