データベース用語においてのアトミック(atomic: 原子的、不可分)な変更とは、全体として成功か失敗をすることはできるが、部分的にはできない個別の変更のことです。Lispプログラムは単一もしくは複数のバッファーにたいする一連の変更をアトミック変更グループ(atomic change group)にすることができます。これはその一連の変更全体がそれらのバッファーに適用されるか、またはエラーの場合は何も適用されないかの、いずれかであることを意味します。
すでにカレントであるような単一のバッファーにたいしてこれを行うには、以下のように単に変更を行うコードの周囲にatomic-change-group
の呼び出しを記述します:
(atomic-change-group (insert foo) (delete-region x y))
atomic-change-group
のbody内部でエラー(またはその他の非ローカルexit)が発生した場合には、そのbodyの実行の間にそのバッファーでのすべての変更が行われなかったことになります。この類の変更グループは他のバッファーには影響を与えず、それらのバッファーにたいする変更はそのまま残されます。
さまざまなバッファー内で行った変更から1つのアトミックグループを構成する等、より複雑な何かを必要とする場合には、atomic-change-group
が使用する、より低レベルな関数を直接呼び出さなければなりません。
この関数はbuffer (デフォルトはカレントバッファー)にたいする変更グループをセットアップする。これはその変更グループを表すhandleをリターンする。変更グループをactivateしたり、その後でそれを完了するためにはこのhandleを使用しなければならない。
変更グループを使用するためには、それをactivate(アクティブ化)しなければなりません。これはbufferのテキストを変更する前に行わなければなりません。
これはhandleが指定する変更グループをactiveにする。
変更グループをactivateした後には、そのバッファー内で行ったすべての変更は変更グループの一部となります。そのバッファー内で目論んでいたすべての変更を行ったら、変更グループをfinish(完了)しなければなりません。すべての変更を受け入れる(確定する)か、すべてをキャンセルするという2つの方法により、これを行うことができます。
この関数はhandleにより指定される変更グループ内のすべての変更にたいして、finalizeすることにより変更を受け入れる。
この関数はhandleにより指定される変更グループ内のすべての変更をキャンセルしてundoする。
undo-amalgamate-change-group
を使用すれば、いくつか、あるいはすべての変更をundo
コマンド(アンドゥを参照)の対象として単一の単位とみなせる変更グループにすることができます。
handleにより識別される状態以降にお子なわれた変更グループへの変更をすべてまとめる。この関数はhandleにより記述された状態以降の変更にたいするアンドゥレコード間のアンドゥ境界すべてを削除する。handleは通常はprepare-change-group
がリターンしたハンドルであり、この場合には変更先頭以降のすべての変更は、単一のアンドゥ単位にまとめられる。
グループが常に確実にfinishされるようにするために、コードではunwind-protect
を使用するべきです。activate-change-group
の呼び出しは、実行直後にユーザーがC-gをタイプする場合に備えてunwind-protect
内部にあるべきです(これがprepare-change-group
とactivate-change-group
が別関数となっている1つの理由。なぜなら通常はunwind-protect
開始前にprepare-change-group
を呼び出すであろうから)。グループを一度finishしたら、そのhandleを再度使用してはなりません。特に同じ変更グループを2回finishしないでください。
複数バッファー変更グループ(multibuffer change
group)を作成するためには、カバーしたいバッファーそれぞれでprepare-change-group
を一度呼び出してから、以下のようにリターン値を結合するためにnconc
を使用してください:
(nconc (prepare-change-group buffer-1) (prepare-change-group buffer-2))
その後は1回のactivate-change-group
呼び出しで複数変更グループをアクティブにして、1回のaccept-change-group
かcancel-change-group
呼び出しでそれをfinishしてください。
同一バッファーにたいするネストされた複数の変更グループ使用は、あなたが期待するであろう通りに機能します。同一バッファーにたいするネストされていない変更グループの使用によりEmacsが混乱した状態になるので、これが発生しないようにしてください。与えられた何らかのバッファーにたいして最初に開始した変更グループは最後にfinishする変更グループです。
Emacsはbuffer-undo-list
のcdrそれぞれを辿ることにより、最終的にはprepare-change-group
の呼び出し時にセットされていたコンスに到達できると仮定して変更グループを追跡します。
buffer-undo-list
にそのコンスが含まれていなければEmacsはすべての変更グループの追跡を失い、結果として変更グループのキャンセル時にエラーとなります。これを回避するためには、変更グループがアクティブなときに、そのような方法でundoリストを編集するかもしれない関数、特にundo-auto-amalgamate
を呼び出すdelete-char
のような“amalgamating(融合化)”なコマンドを呼び出さないでください。