一般的に、Emacsセッションには多くのバッファが存在します。常にそのうちの1つがカレントバッファ――ほとんどの編集が行われるバッファ――として指定されています。テキストの確認や変更を行うプリミティブの多くは、暗黙的にカレントバッファに対して動作します(Textを参照)。
通常、選択中のウィンドウ(ウィンドウの選択を参照)に表示されるバッファが現在のバッファとなりますが、必ずしもそうとは限りません。Lispプログラムは、画面上の表示内容を変更することなく、任意のバッファを一時的に現在のバッファとして指定し、その内容を操作することができます。現在のバッファを指定するための最も基本的な関数はset-bufferです。
この関数は、現在のバッファを返します。
(current-buffer)
⇒ #<buffer buffers.texi>
この関数は buffer-or-name をカレントバッファに設定します。buffer-or-name は既存のバッファ、または既存のバッファ名である必要があります。戻り値は、カレントに設定されたバッファです。
この関数はバッファをどのウィンドウにも表示しないため、ユーザーが必ずしもバッファを確認できるとは限りません。しかし、これでLispプログラムはバッファを操作できるようになります。
編集コマンドがエディタのコマンドループに戻ると、Emacsは選択中のウィンドウに表示されているバッファに対して自動的に set-buffer を呼び出します(ウィンドウの選択を参照)。これは混乱を防ぐためです。これにより、Emacsがコマンドを読み取る際に、カーソルがあるバッファが、そのコマンドが適用されるバッファになることが保証されます(コマンドループを参照)。したがって、set-buffer を使用して視覚的に別のバッファに切り替えるべきではありません。その場合は、ウィンドウ内のバッファへの切り替えで説明されている関数を使用してください。
Lisp関数を記述する際は、操作後に現在のバッファを復元するというコマンドループのこの挙動に依存しないでください。編集コマンドは、コマンドループからだけでなく、他のプログラムからもLisp関数として呼び出されることがあります。サブルーチンが現在のバッファを変更しない方が、呼び出し側にとって便利です(もちろん、それがサブルーチンの目的である場合は除きます)。
別のバッファで一時的に操作するには、set-bufferをsave-current-buffer形式で記述します。以下に、コマンドappend-to-bufferの簡略版を例として示します。
(defun append-to-buffer (buffer start end)
"Append the text of the region to 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)
"Append the text of the region to 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
を使うことに頼らないでください。誤ったバッファが現在の状態である間に終了が発生した場合、それでは対処できないためです。例えば、前述の例では、次のようにするのは誤りでした:
(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 を用いると、通常の評価だけでなく、終了やエラー、throw も正しく処理できます。
save-current-buffer 特殊形式は、現在のバッファの識別子を保存し、body 形式を評価し、最後にそのバッファを現在のバッファとして復元します。戻り値は body の最後の形式の値となります。throw
による異常終了やエラーが発生した場合でも、現在のバッファは復元されます(非局所終了 を参照)。
save-current-buffer
を抜ける時点で、それまでカレントだったバッファが破棄されていた場合、当然ながらそのバッファが再びカレントになることはありません。代わりに、抜ける直前にカレントだったバッファがそのままカレントとして残ります。
with-current-buffer マクロは、現在のバッファの識別情報を保存し、buffer-or-name をカレントに設定し、body
のフォームを評価し、最後に現在のバッファを復元します。buffer-or-name
には、既存のバッファまたは既存のバッファ名を指定する必要があります。
戻り値は、body 内の最後のフォームの値です。throw による異常終了やエラーが発生した場合でも、現在のバッファは復元されます(非局所終了を参照)。
with-temp-buffer マクロは、一時バッファを現在のバッファとして body
形式を評価します。現在のバッファの識別情報を保存し、一時バッファを作成してそれを現在のバッファに設定し、body 形式を評価し、最後に一時バッファを破棄しながら以前の現在のバッファを復元します。
デフォルトでは、このマクロによって作成されるバッファにアンドゥ情報(Undoを参照)は記録されません(ただし、必要に応じて body
で有効にできます)。また、一時バッファではフック kill-buffer-hook、kill-buffer-query-functions(Killing Buffersを参照)、および buffer-list-update-hook(The Buffer Listを参照)は実行されません。
戻り値は、body における最後のフォームの値です。最後のフォームに (buffer-string) を指定することで、一時バッファの内容を返すことができます。
throw による異常終了やエラーが発生した場合でも、現在のバッファは復元されます(非局所的な終了を参照)。
ファイルへの書き込み
の with-temp-file も参照してください。