一般的に1つのEmacsセッション内には多くのバッファーが存在します。常にそれらのうちの1つがカレントバッファー(current buffer)に指定されます。カレントバッファーとは、ほとんどの編集が行われるバッファーのことです。テキストを調べたり変更するプリミティブのほとんどは暗黙にカレントバッファーにたいして処理を行います(テキストを参照)。
通常は選択されたウィンドウ(ウィンドウの選択を参照)の中に表示されるバッファーがカレントバッファーですが、常にそうであるとは言えません。Lispプログラムはバッファーのコンテンツを処理するために、スクリーン上に表示されているものを変更することなく任意のバッファーを一時的にカレントに指定できます。カレントバッファーの指定にたいするもっとも基本的な関数はset-buffer
です。
この関数はカレントバッファーをリターンする。
(current-buffer) ⇒ #<buffer buffers-ja.texi>
この関数はbuffer-or-nameをカレントバッファーにする。buffer-or-nameは既存のバッファー、または既存のバッファーの名前でなければならない。リターン値はカレントになったバッファー。
この関数はそのバッファーをどのウィンドウにも表示しないので、必然的にユーザーはそのバッファーを見ることはできない。しかしLispプログラムはその後に、そのバッファーにたいして処理を行うことになるだろう。
編集コマンドがエディターコマンドループにリターンする際、Emacsは選択されたウィンドウ(ウィンドウの選択を参照)の中に表示されているバッファーにたいして、自動的にset-buffer
を呼び出します。これは混乱を防ぐためであり、これによりEmacsがコマンドを読み取るときにカーソルのあるバッファーが、コマンドを適用されるバッファーになることが保証されます(コマンドループを参照)。したがって異なるバッファーを指示して切り替える場合にはset-buffer
を使用するべきではありません。これを行うためにはウィンドウ内のバッファーへの切り替えで説明されている関数を使用してください。
Lisp関数を記述する際は、処理後にカレントバッファーをリストアするためにコマンドループのこの振る舞いに依存しないでください。編集コマンドはコマンドループだけではなく、他のプログラムからLisp関数としても呼び出されます。呼び出し側にとっては、そのサブルーチンがカレントだったバッファーを変更しないほうが便利です(もちろんそれがサブルーチンの目的でない場合)。
他のバッファーにたいして一時的に処理を行うには、save-current-buffer
フォーム内にset-buffer
を配置します。以下の例はコマンドappend-to-buffer
の簡略版です:
(defun append-to-buffer (buffer start end) "リージョンのテキストをBUFFERに追加する" (interactive "BAppend to buffer: \nr") (let ((oldbuf (current-buffer))) (save-current-buffer (set-buffer (get-buffer-create buffer)) (insert-buffer-substring oldbuf start end))))
ここではカレントバッファーを記録するためにローカル変数にバインドしてから、後でsave-current-buffer
がそれを再びカレントにするようにアレンジしています。次にset-buffer
が指定されたバッファーをカレントにして、insert-buffer-substring
が元のバッファーの文字列を指定された(今はカレントの)バッファーにコピーします。
かわりにwith-current-buffer
マクロを使用することもできます:
(defun append-to-buffer (buffer start end) "BUFFERにリージョンのテキストを追加する" (interactive "BAppend to buffer: \nr") (let ((oldbuf (current-buffer))) (with-current-buffer (get-buffer-create buffer) (insert-buffer-substring oldbuf start end))))
いずれのケースでも、追加されるバッファーが偶然他のウィンドウに表示されていると、次回の再表示でそのテキストがどのように変更されたか表示されるでしょう。どのウィンドウにも表示されていなければスクリーン上で即座に変更を目にすることはありません。コマンドはバッファーを一時的にカレントにしますが、そのことがバッファーの表示を誘発する訳ではありません。
バッファーローカルなバインディングをもつ変数にたいして、(let
や関数引数などで)ローカルバインディングを作成する場合には、そのローカルバインディングのスコープの最初と最後で同じバッファーがカレントとなることを確認してください。そうしないと、あるバッファーではバインドして他のバッファーではバインドされないことになるかもしれません!
set-buffer
の使用において、カレントバッファーが戻ることに依存しないでください。なぜなら間違ったバッファーがカレントのときにquitが発生した場合には、その処理は行われないでしょう。たとえば上記の例に倣うと以下は間違ったやり方です:
(let ((oldbuf (current-buffer))) (set-buffer (get-buffer-create buffer)) (insert-buffer-substring oldbuf start end) (set-buffer oldbuf))
例で示したようにsave-current-buffer
やwith-current-buffer
を使用すれば、quitやthrow
を通常の評価と同様に処理できます。
スペシャルフォームsave-current-buffer
はカレントバッファーの識別を保存してbodyフォームを評価し、最後にそのバッファーをカレントにリストアする。リターン値はbody内の最後のフォームの値。throw
やエラーを通じた異常exitの場合にもカレントバッファーはリストアされる(非ローカル脱出を参照)。
カレントとして使用されていたバッファーがsave-current-buffer
によるexit時にkillされていたら、当然それが再びカレントとなることはない。かわりにexit直前にカレントバッファーが何であれ、それがカレントになる。
with-current-buffer
マクロはカレントバッファーの識別を保存してbuffer-or-nameをカレントにし、bodyフォームを評価してから最後にカレントバッファーをリストアする。buffer-or-nameには既存のバッファー、または既存のバッファー名を指定しなければならない。
リターン値はbody内の最後のフォームの値。throw
やエラーを通じた異常exitの場合にも、カレントバッファーはリストアされる(非ローカル脱出を参照)。
with-temp-buffer
マクロは一時的なバッファーをカレントバッファーとしてbodyフォームを評価する。これはカレントバッファーの識別を保存して一時的なバッファーを作成、それをカレントとしてbodyフォームを評価して、一時バッファーをkillする間に以前のカレントバッファーをリストアする。
このマクロが作成したバッファーでは、デフォルトではアンドゥ情報(アンドゥを参照)は記録されない(が必要ならbodyで有効にできる)。また一時バッファーはkill-buffer-hook
、kill-buffer-query-functions
(バッファーのkillを参照)、buffer-list-update-hook
(バッファーリストを参照)のフックも実行しない。
リターン値はbody内の最後のフォームの値。最後のフォームとして(buffer-string)
を使用することにより、一時バッファーのコンテンツをリターンできる。
throw
やエラーを通じた異常exitの場合にも、カレントバッファーはリストアされる(非ローカル脱出を参照)。
Writing to
Filesのwith-temp-file
も参照のこと。