これまでのサブセクションによってバッファーを表示するためには、display-buffer
にいくつかのディスプレイアクションを提供しなければならないことがわかりました(バッファーを表示するウィンドウの選択を参照)。まったくカスタマイズしていないEmacsでは、これらのアクションはdisplay-buffer-fallback-action
によってウィンドウの再利用、同一フレーム上での新たなウィンドウのポップアップ、そのバッファーを以前に表示したウィンドウの使用、新たなフレームをポップアップして何らかのウィンドウを使用するという優先順で指定されます(display-buffer-fallback-action
いより命名される残りのアクションは未カスタマイズのEmacsではvoidであることに注意)。
以下のフォームを考えてください:
(display-buffer (get-buffer-create "*foo*"))
このフォームをカスタマイズされていないEmacsの*scratch*バッファーで評価すると、通常はすでに*foo*を表示しているウィンドウの再利用は失敗しますが、新たなウィンドウのポップアップは成功するでしょう。そこで同じフォームを再度評価すると、今度はdisplay-buffer
はすでに*foo*を表示しているウィンドウを再利用して視覚的な変化は生じません。なぜならそれは許容され得るアクションであるとともに、すべての許容され得るアクションの中でもっとも高い優先度をもつからです。
選択されたフレームに十分なスペースがなければ、新たなウィンドウのポップアップは失敗します。カスタマイズされていないEmacsでは、通常はフレームに2つのウィンドウがすでに存在すれば失敗します。たとえば今度はC-x 1の後にC-x 2をタイプしてからもう一度フォームを評価すると、*foo*は下側のウィンドウに表示されるはずです(
display-buffer
は単に“何らか”のウィンドウを使用した)。C-x 2をタイプする前にC-x oをタイプしていれば、*foo*は上側のウィンドウに表示されるでしょう。なぜなら“何らか”のウィンドウとは“最近もっとも使用されていない”ウィンドウという意味であり、選択されたウィンドウが最近もっとも使用されていないウィンドウになるのは、それがフレームで唯一のウィンドウの場合だけだからです。
C-x oをタイプせずに*foo*が下側のウィンドウに表示されているとしましょう。下側のウィンドウに移動するためにC-x oの後にC-x leftをタイプして、再びフォームを評価してみます。すると*foo*は同じ下側のウィンドウに表示されるはずです。なぜなら*foo*は以前にそのウィンドウで表示されているので何らかのウィンドウのかわりにそのウィンドウが選択されるからです。
ここまではカスタマイズしていないEmacsのデフォルトの動作を観察してきました。この動作のカスタマイズの仕方を確認するために、オプションdisplay-buffer-base-action
について考えてみましょう。これは概念的に任意のバッファーの表示に影響を与える、非常に大まかなカスタマイズを提供します。これはdisplay-buffer-fallback-action
により提供されるアクションの並び替えや、提供されていないもののユーザーの編集方法により密接に適合するアクションを追加することにより、display-buffer-fallback-action
の補強に使用することができます。しかしデフォルトの動作をより深く変更するためにも使用できます。
ルールとして別フレームにバッファーを表示することを好むユーザーを考えてみましょう。そのようなユーザーなら以下のようなカスタマイズを行うかもしれません:
(setopt display-buffer-base-action '((display-buffer-reuse-window display-buffer-pop-up-frame) (reusable-frames . 0)))
このセッティングによりdisplay-buffer
はバッファーを表示するウィンドウを探すために、まず可視のフレームとアイコン化されたフレームを探して、そのようなフレームが存在しなければ新たなフレームをポップアップします。グラフィカルなシステム上で*scratch*を表示しているウィンドウでC-x 1をタイプして例のdisplay-buffer
フォームを評価して動作を観察できます。これは通常はルートウィンドウに*foo*を表示するフレームを新たに作成(およびフォーカスを付与)します。このフレームをアイコン化して例のフォームを再度評価すると、display-buffer
は新たなフレーム(通常はフレームをraiseしてフォーカスを付与)のウィンドウを再利用するでしょう。
display-buffer
は新たなフレームの作成に失敗した場合のみdisplay-buffer-fallback-action
が提供するアクション(ウィンドウ再利用の再試行、新たなウィンドウのポップアップ等)を適用します。以下のフォームでフレーム作成を簡単に失敗させることができます:
(let ((pop-up-frame-function 'ignore)) (display-buffer (get-buffer-create "*foo*")))
新たなフレーム作成に失敗してかわりにフォールバックアクションの使用を観察した直後にこのフォームを忘れてしまうでしょう。
display-buffer-base-action
のカスタマイズにおいてdisplay-buffer-reuse-window
は冗長に思えることに注意してください。なぜならすでにdisplay-buffer-reuse-window
はdisplay-buffer-fallback-action
の一部であり、いずれにせよフォールバックアクションで試みられるはずだからです。しかしこれはdisplay-buffer-pop-up-frame
が優先順ですでに優っていた時点で、display-buffer-base-action
がdisplay-buffer-fallback-action
より優先されることにより失敗するでしょう。実際のところ:
(setopt display-buffer-base-action '(display-buffer-pop-up-frame (reusable-frames . 0)))
はdisplay-buffer
が常に新たなフレームをポップアップして、これはおそらくユーザーが望んでいない動作です。
ここまではユーザーがdisplay-buffer
のデフォルト動作をカスタマイズする方法だけを示しました。今度はアプリケーションがdisplay-buffer
の動作を変更する方法について見てみましょう。これを行う正規の手順はdisplay-buffer
やpop-to-buffer
のようなdisplay-buffer
を呼び出す関数のaction引数を使用する方法です(ウィンドウ内のバッファーへの切り替えを参照)。
あるアプリケーションが(新たなウィンドウにユーザーを即座に注目させるために)可能なら選択されたウィンドウの下、それが失敗したらフレームの最下ウィンドウにに*foo*を表示したいと仮定してみましょう。これは以下のような呼び出しで行うことができます:
(display-buffer (get-buffer-create "*foo*") '((display-buffer-below-selected display-buffer-at-bottom)))
この新しい変更されたフォームがどのように機能するか確認するために*foo*を表示しているすべてのフレームを削除してから、*scratch*を表示中のウィンドウでC-x 1の後にC-x 2をタイプしてから、続けてそのフォームを評価してみてください。display-buffer
は上側のウィンドウを分割して、新たなウィンドウに*foo*を表示するはずです。C-x 2の後にC-x oをタイプした場合には、display-buffer
はかわりに最下にあるウィンドウを分割するでしょう。
今度は新たなフォームを評価する前に、(たとえば選択されたウィンドウで(fit-window-to-buffer)
を評価して)選択されたウィンドウを可能なかぎり小さくしたとします。この場合にはdisplay-buffer
は選択されたウィンドウの分割に失敗して、フレームの最下に効果的に*foo*を表示するために、かわりにフレームのルートウィンドウを分割するでしょう。
いずれの場合においても新たなフォームの2回目の評価では、すでに*foo*を表示しているウィンドウの再利用を試みるはずです。これはaction引数が提供するどちらの関数も、そのようなウィンドウの使用を最初に試みるからです。
action引数をセットすることにより、アプリケーションはdisplay-buffer-base-action
のすべてのカスタマイゼーションを効果的に無効にします。今度はユーザーはアプリケーションの選択を受け入れるか、以下のようにオプションdisplay-buffer-alist
をさらにカスタマイズすることができます:
(setopt display-buffer-alist '(("\\*foo\\*" (display-buffer-reuse-window display-buffer-pop-up-frame))))
*foo*がどこにも表示されていない設定で新たな変更版のフォームを試みると、display-buffer
のactionを完全に無視して別フレームに*foo*が表示されます。
display-buffer-alist
の仕様において,reusable-frames
アクションalistの指定を気にしていない点に注意してください。display-buffer
は常に最初に見つかったウィンドウ、この場合ではdisplay-buffer-base-action
で指定されたウィンドウを採用します。しかし異なる仕様を使用したいとき、たとえば再利用可能なウィンドウから*foo*を表示中のアイコン化されたフレームを除外したければ個別にそれを指定する必要があります:
(setopt display-buffer-alist '(("\\*foo\\*" (display-buffer-reuse-window display-buffer-pop-up-frame) (reusable-frames . visible))))
これを試せば繰り返し*foo*の表示を試みた場合に、フレームが可視のときだけフレームの再利用に成功することに気がつくでしょう。
上記の例によりアプリケーションが選択したaction引数を無視するという単一の目的にたいしてユーザーがdisplay-buffer-alist
をカスタマイズできるという結論が導かれるかもしれません。そのような結論は正しくありません。display-buffer-alist
は表示がaction引数によってもガイドされるかどうかに関わらず、ユーザーが好む方法で特定のバッファーの表示方法を指示するための標準オプションです。
しかし2つの主要な観点から、display-buffer-alist
のカスタマイズはdisplay-buffer-base-action
のカスタマイズとは異なると合理的に結論づけることができます。display-buffer-alist
のカスタマイズはdisplay-buffer
のaction引数をオーバーライドして、影響を受けるバッファーを明示的に指定できることからより強力です。実際のところ*foo*のカスタマイズによって他のバッファーの表示には何も影響がありません。たとえば、
(display-buffer (get-buffer-create "*bar*"))
はdisplay-buffer-base-action
とdisplay-buffer-fallback-action
のセッティングだけに管理されます。
ここで例を止めることもできますが、Lispプログラムにはdisplay-buffer-alist
にたいする任意のカスタマイズの無効化に使用できる取って置きの切り札があります。その切り札display-buffer-overriding-action
は以下のようにdisplay-buffer
呼び出しの前後でバインドすることができます:
(let ((display-buffer-overriding-action '((display-buffer-same-window)))) (display-buffer (get-buffer-create "*foo*") '((display-buffer-below-selected display-buffer-at-bottom))))
このフォームの評価により通常はaction引数や任意のユーザーカスタマイゼーションとは無関係に、選択されたウィンドウに*foo*が表示されます(通常はアプリケーションがactionを提供する必要もないが、ここではオーバーライドされる事実を示すために提供されている)。
ここで提供したカスタマイゼーションで*foo*の表示を試みたアクション関数のリストを調べれば、それが実例になるかもしれません。そのリスト(何がそれを追加したかと後続の要素を含む)は:
(display-buffer-same-window ;; `display-buffer-overriding-action' display-buffer-reuse-window ;; `display-buffer-alist' display-buffer-pop-up-frame display-buffer-below-selected ;; ACTION argument display-buffer-at-bottom display-buffer-reuse-window ;; `display-buffer-base-action' display-buffer-pop-up-frame display-buffer--maybe-same-window ;; `display-buffer-fallback-action' display-buffer-reuse-window display-buffer--maybe-pop-up-frame-or-window display-buffer-in-previous-window display-buffer-use-some-window display-buffer-pop-up-frame)
ここで列挙した内部関数の中でdisplay-buffer--maybe-pop-up-frame-or-window
が実際にdisplay-buffer-pop-up-window
を実行しているにも関わらず、display-buffer--maybe-same-window
が効果的に無視されていることに注意してください。
アクション関数の各呼び出しにおいて渡されるアクションalistは:
((reusable-frames . visible) (reusable-frames . 0))
これは上述のdisplay-buffer-alist
の2つ目の仕様を使用して、display-buffer-base-action
が提供する仕様をオーバーライドすることを示しています。これをユーザーが以下のように記述したと考えてみましょう
(setopt display-buffer-alist '(("\\*foo\\*" (display-buffer-reuse-window display-buffer-pop-up-frame) (inhibit-same-window . t) (reusable-frames . visible))))
この場合にはalistのinhibit-same-window
エントリーはdisplay-buffer-overriding-action
からdisplay-buffer-same-window
仕様を成功裏に無効化して、display-buffer
は別フレームに*foo*を表示するでしょう。この点においてdisplay-buffer-overriding-action
をより堅牢にするためには、アプリケーションはたとえば以下のように適切なinhibit-same-window
エントリーも指定する必要があるでしょう:
(let ((display-buffer-overriding-action '(display-buffer-same-window (inhibit-same-window . nil)))) (display-buffer (get-buffer-create "*foo*")))
最後の例ではバッファーを表示するウィンドウの選択で説明したようにアクション関数の優先順は固定ではあるものの、優先順で低位のディスプレイアクションが指定したアクションalistのエントリーが、より高位のディスプレイアクションの実行に影響を与えれれることを示しています。