Next: , Previous: , Up: Displaying Buffers   [Contents][Index]


28.13.5 アクション関数の優先順

これまでのサブセクションによってバッファーを表示するためには、display-bufferにいくつかのディスプレイアクションを提供しなければならないことがわかりました(Choosing Windowを参照)。まったくカスタマイズしていない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の補強に使用することができます。しかしデフォルトの動作をより深く変更するためにも使用できます。

ルールとして別フレームにバッファーを表示することを好むユーザーを考えてみましょう。そのようなユーザーなら以下のようなカスタマイズを行うかもしれません:

(customize-set-variable
 '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-windowdisplay-buffer-fallback-actionの一部であり、いずれにせよフォールバックアクションで試みられるはずだからです。しかしこれはdisplay-buffer-pop-up-frameが優先順ですでに優っていた時点で、display-buffer-base-actiondisplay-buffer-fallback-actionより優先されることにより失敗するでしょう。実際のところ:

(customize-set-variable
 'display-buffer-base-action
 '(display-buffer-pop-up-frame (reusable-frames . 0)))

display-bufferに新たなフレームをポップアップして、これはおそらくユーザーが望んでいない動作です。

ここまではユーザーdisplay-bufferのデフォルト動作をカスタマイズする方法だけを示しました。今度はアプリケーションdisplay-bufferの動作を変更する方法について見てみましょう。これを行う正規の手順はdisplay-bufferpop-to-bufferのようなdisplay-bufferを呼び出す関数のaction引数を使用する方法です(Switching Buffersを参照)。

あるアプリケーションが(新たなウィンドウにユーザーを即座に注目させるために)可能なら選択されたウィンドウの下、それが失敗したらフレームの最下ウィンドウにに*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をさらにカスタマイズすることができます:

(customize-set-variable
 'display-buffer-alist
 '(("\\*foo\\*"
    (display-buffer-reuse-window display-buffer-pop-up-frame))))

*foo*がどこにも表示されていない設定で新たな変更版のフォームを試みると、display-bufferactionを完全に無視して別フレームに*foo*が表示されます。

display-buffer-alistの仕様において,reusable-framesアクションalistの指定を気にしていない点に注意してください。display-bufferは常に最初に見つかったウィンドウ、この場合ではdisplay-buffer-base-actionで指定されたウィンドウを採用します。しかし異なる仕様を使用したいとき、たとえば再利用可能なウィンドウから*foo*を表示中のアイコン化されたフレームを除外したければ個別にそれを指定する必要があります:

(customize-set-variable
 '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-bufferaction引数をオーバーライドして、影響を受けるバッファーを明示的に指定できることからより強力です。実際のところ*foo*のカスタマイズによって他のバッファーの表示には何も影響がありません。たとえば、

(display-buffer (get-buffer-create "*bar*"))

display-buffer-base-actiondisplay-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が提供する仕様をオーバーライドすることを示しています。これをユーザーが以下のように記述したと考えてみましょう

(customize-set-variable
 '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*")))

最後の例ではChoosing Windowで説明したようにアクション関数の優先順は固定ではあるものの、優先順で低位のディスプレイアクションが指定したアクションalistのエントリーが、より高位のディスプレイアクションの実行に影響を与えれれることを示しています。