プログラム中の限定された部分で、ポイントを“一時的”に移動するのが便利なことが時折あります。これはエクスカーション(excursion:
遠足、小旅行)と呼ばれ、スペシャルフォームsave-excursion
により行います。この構成は、初期のカレントバッファー自体、ポイントおよびマークの値を記憶して、そのエクスカーション完了時にそれらをリストアします。これはプログラムのある部分において、プログラムの他の部分に影響を与えることなくポイントを移動する標準的な手段であり、EmacsのLispソース内では何度も使用されています。
カレントバッファー自体のみの保存やリストアが必要なら、かわりにsave-current-buffer
やwith-current-buffer
を使用してください(Current Bufferを参照)。ウィンドウ構成の保存やリストアが必要なら、Window ConfigurationsとFrame Configurationsで説明されているフォームを参照してください。
このスペシャルフォームは、カレントバッファー自体、およびポイント値とマーク値を保存してbodyを評価し、最後にバッファーおよび保存したポイントとマークの値をリストアする。throw
またはエラーを通じたアブノーマルexit(Nonlocal Exitsを参照)の場合でも、保存された3つすべての値はリストアされる。
save-excursion
がリターンする値はbody内の最後のフォームの結果、またはbodyフォームが与えられなければnil
をリターンする。
save-excursion
は、エクスカーション開始時にカレントだったバッファーのポイントとマークだけを保存ため、そのエクスカーション中に変更された他のバッファーのポイントおよび/またはマークは、その後も効果が残るでしょう。これはしばしば予期せぬ結果を招くので、エクスカーション中にset-buffer
を呼び出した場合、バイトコンパイラーは警告を発します:
Warning: Use `with-current-buffer' rather than save-excursion+set-buffer
このような問題を回避するためには、以下の例のように望むカレントバッファーをセット後にのみsave-excursion
を呼び出すべきです:
(defun append-string-to-buffer (string buffer) "BUFFER末尾にSTRINGを追加" (with-current-buffer buffer (save-excursion (goto-char (point-max)) (insert string))))
同様にsave-excursion
はswitch-to-buffer
のような関数が変更したウィンドウ/バッファーの対応をリストアしません。
警告:
保存されたポイント値に隣接する通常のテキスト挿入は、それがすべてのマーカーを再配置するのと同じように、保存されたポイントカーを再配置します。より正確には保存される値は挿入タイプnil
のマーカーです。Marker Insertion Typesを参照してください。したがって保存されたポイント値は、リストア時には通常は挿入されたテキストの直前になります。
たとえsave-excursion
がマーク位置を保存しても、バッファーを変更する関数がdeactivate-mark
をセットするのを禁止しないため、そのコマンド完了後にマークの非アクティブ化が効力を発揮します。The Markを参照してください。