ほとんどのバッファにはアンドゥリストがあり、バッファのテキストに加えられたすべての変更が記録され、それらを元に戻せるようになっています。(アンドゥリストを持たないバッファは通常、Emacsがアンドゥを有用ではないとみなす特殊目的のバッファです。特に、名前がスペースで始まるバッファは、デフォルトでアンドゥ記録がオフになっています。バッファ名を参照してください。)バッファ内のテキストを変更するすべてのプリミティブは、変数buffer-undo-listにあるアンドゥリストの先頭に要素を自動的に追加します。
このバッファローカル変数の値は、現在のバッファのアンドゥリストです。t
という値を指定すると、アンドゥ情報の記録が無効になります。
取り消しリストに含めることができる要素には、以下のようなものがあります。
positionこの種の要素はポイントの以前の値を記録しており、この要素をアンドゥするとポイントは position
に移動します。通常のカーソル移動ではいかなるアンドゥ記録も作成されませんが、削除操作では、削除をアンドゥして削除済みテキストを再挿入してもポイントが適切な位置に配置されない場合に、コマンド実行前のポイントの位置を記録するためにこれらのエントリを利用します。コマンドのアンドゥによってポイントを正しく復元する必要がある
Lisp プログラムでは、復元すべき位置を記録するために、明示的に (point) を buffer-undo-list へプッシュすることができます。
(beg . end)この種の要素は、挿入されたテキストの削除方法を示します。挿入時、そのテキストはバッファ内の範囲 beg–end を占有していました。
(text . position)この種の要素は、削除されたテキストを再挿入する方法を示します。削除されたテキスト自体は文字列 text
です。再挿入する位置は (abs position)
です。position
が正の値であれば位置は削除されたテキストの先頭に、そうでなければ末尾にありました。この要素の直後に、0個以上の (marker . adjustment) 要素が続きます。
(t . time-flag)この種の要素は、未変更のバッファが変更されたことを示します。整数ではないLispタイムスタンプであるtime-flagは、current-timeと同じ形式を用いて、訪問済みファイルが以前に訪問または保存された時点での変更時刻を表します。Time of Dayを参照してください。time-flagが0の場合はバッファがいずれのファイルにも対応していないことを意味し、−1の場合は訪問済みファイルが以前は存在しなかったことを意味します。primitive-undoはこれらの値を用いて、バッファを再び未変更としてマークするかどうかを判定します。ファイルの状態がtime-flagと一致する場合にのみ、マークが行われます。
(nil property value beg . end)この種の要素は、テキストプロパティの変更を記録します。変更を取り消すには、次のようにします。
(put-text-property beg end property value)
(marker . adjustment)この種の要素は、周囲のテキストの削除によってマーカー marker が再配置され、adjustment 文字分移動したという事実を記録します。マーカーの位置が、アンドゥリストにおいてその直前にある (text . position) 要素と一致している場合、この要素をアンドゥすると marker − adjustment 文字分移動します。
(apply funname . args)これは拡張可能な元に戻す項目であり、引数 args を指定して funname を呼び出すことで元に戻されます。
(apply delta beg end funname . args)これは拡張可能なアンドゥ項目であり、バッファのサイズをdelta文字分増加させたbegからendの範囲に限定した変更を記録します。引数argsを指定してfunnameを呼び出すことで、この変更をアンドゥできます。
この種の要素により、領域に限定した元に戻す操作が可能となり、その要素が当該領域に属するかどうかを判定できます。
(apply delta (beg . end) funname . args)この種の要素は、前述の形式に似ています。異なる点は、元に戻す際に funname を次のように呼び出すことです。
(apply funname beg2 end2 args)
ここで、beg2 と end2 は beg と end の調整後の値です。関数はこれらの引数を用いて、調整後の領域を基準とした位置を算出できます。
nilこの要素は境界です。2つの境界の間にある要素は変更グループと呼ばれ、通常、各変更グループは1つのキーボードコマンドに対応し、元に戻すコマンドは通常、グループ全体を単位として元に戻します。
この関数は、アンドゥリストに境界要素を追加します。アンドゥコマンドはこのような境界で停止し、連続するアンドゥコマンドは、より前の境界へと遡ってアンドゥを行います。この関数は
nil を返します。
この関数を明示的に呼び出すことは、コマンドの効果を複数の単位に分割する際に有用です。例えば、query-replace は置換が行われるたびに undo-boundary を呼び出すため、ユーザーは個々の置換を一つずつ元に戻すことができます。
しかし、ほとんどの場合、この関数は適切なタイミングで自動的に呼び出されます。
エディタのコマンドループは、各キーシーケンスを実行する直前に自動的に undo-boundary
を呼び出すため、通常、各アンドゥ操作で1つのコマンドによる影響が取り消されます。一部の例外的なコマンドはアマルガミングされます。これらのコマンドは一般的にバッファに軽微な変更を加えるため、20コマンドに1回のみ境界が挿入され、変更をまとめて取り消すことができます。デフォルトでは、自己挿入入力文字を生成する
self-insert-command(ユーザーレベルの挿入コマンドを参照)と、文字を削除する delete-char(テキストの削除を参照)はアマルガミング対象となります。例えば、post-command-hook の関数が current-buffer
以外のバッファに影響を与える場合など、1つのコマンドが複数のバッファの内容に影響する場合、影響を受けた各バッファで undo-boundary が呼び出されます。
この関数は、アマルガミングコマンドの前に呼び出すことができます。このような呼び出しが連続して行われた場合、直前の undo-boundary を削除します。
統合可能な変更の最大数は、amalgamating-undo-limit
変数によって制御されます。この変数が 1 の場合、変更は統合されません。
Lispプログラムでは、undo-amalgamate-change-groupを呼び出すことで、一連の変更を単一の変更グループにまとめることができます(アトミック変更グループを参照)。なお、amalgamating-undo-limitはこの関数によって生成されたグループには影響を与えません。
プロセスバッファなどの一部のバッファは、コマンドが実行されていないときでも変化することがあります。このような場合、通常はこの変数のタイマーによって定期的に
undo-boundary が呼び出されます。この変数を nil 以外に設定すると、この動作を防ぐことができます。
この変数は通常 nil ですが、元に戻すコマンドはこれを t
にバインドします。これは、さまざまな種類の変更フックが、元に戻す目的で呼び出されていることを判別できるようにするためです。
これは、アンドゥリストの要素をアンドゥするための基本機能です。listの先頭count個の要素をアンドゥし、listの残りを返します。
primitive-undo
は、バッファを変更する際に、バッファのアンドゥリストに要素を追加します。アンドゥコマンドは、一連のアンドゥ操作の開始時にアンドゥリストの値を保存することで、混乱を防ぎます。その後、アンドゥ操作ではこの保存された値を利用し、更新します。アンドゥによって追加された新しい要素はこの保存値に含まれないため、以降のアンドゥ操作に支障をきたすことはありません。
この関数は undo-in-progress をバインドしません。
このマクロは、bodyの実行中に挿入されたすべてのアンドゥ境界を削除し、単一のステップとしてアンドゥできるようにします。
一部のコマンドは、実行後もリージョンをアクティブなままにするため、そのコマンドの選択的な元に戻す操作に支障をきたすことがあります。このようなコマンドの直後に
undo を呼び出した際にアクティブなリージョンを無視させるには、コマンドの関数シンボルのプロパティ
undo-inhibit-region に nil 以外の値を設定してください。標準シンボルプロパティ を参照してください。