フレームのもっとも単純な形式では常にバッファー表示に使用可能な単一のウィンドウが収容されています。結果としてdisplay-buffer
のもっとも最近の呼び出しは、常にそのウィンドウへのバッファーの配置に成功した呼び出しとなります。
そのようなフレームを処理することは実際的ではないので、デフォルトではEmacsはフレームサイズのデフォルト値、split-height-threshold
やsplit-width-threshold
のオプションにより制御される、より複雑なレイアウトを許容しています。そのフレームでまだ表示されていないバッファーを表示すると、フレーム上の単一ウィンドウを分割するか、2つのウィンドウのいずれかを(再)利用します。
これらのしきい値のいずれかをカスタマイズしたり手動でフレームのレイアウトを変更するとデフォルトの動作は棄却されます。非nil
のaction引数でdisplay-buffer
を呼び出したり、前のサブセクションに示したオプションのいずれかをユーザーがカスタマイズした際にもデフォルト動作は棄却されます。display-buffer
を習得次第、表示可能なディスプレイアクションとフレイムレイアウト結果の膨大さにフラストレーションを覚えるかもしれません。
しかしバッファー表示関数の使用を控えてウィンドウのウィンドウの分割と削除のメタファーに逆行するのは良い考えではありません。Lispプログラムやユーザーにたいしてバッファー表示関数は、異なるニーズを調整するフレームワークを提供します。ウィンドウの分割と削除にたいする同等なフレームワークは存在しません。バッファー表示関数ではフレームからバッファーを削除する際に、少なくともフレームレイアウトを部分的に後からリストアすることが可能です(ウィンドウのquitを参照)。
上述したフラストレーションを埋め合わせるとともに、文字通りフレームのウィンドウ間でバッファーが失われることを避けるために、以下にいくつのガイダンスを示します。
ディスプレイアクションの記述はアクション関数とアクションalistを1つの巨大なリストにまとめる必要があるので多大な苦痛をともなう恐れがある(歴史的な理由によってdisplay-buffer
の引数として個別にサポートすることができなかった)。以下のリストのような基本形式を覚えておくと便利かもしれない:
'(nil (inhibit-same-window . t))
アクション関数なしのアクションalistエントリーだけを指定する。これの唯一の目的は、どこかで指定されたdisplay-buffer-same-window
関数が同一ウィンドウ内でのバッファー表示を抑制すること。前のサブセクションの最後の例も参照のこと。
'(display-buffer-below-selected)
一方こちらは1つのアクション関数と空のアクションalistを指定する。上記2つの指定の効果を1つ組み合わせるためには以下のようなフォームを記述
'(display-buffer-below-selected (inhibit-same-window . t))
別のアクション関数の追加は以下のように記述
'((display-buffer-below-selected display-buffer-at-bottom) (inhibit-same-window . t))
別のアクションalistを追加するには以下のように記述
'((display-buffer-below-selected display-buffer-at-bottom) (inhibit-same-window . t) (window-height . fit-window-to-buffer))
最後のフォームは以下の方法によりdisplay-buffer
のaction関数に使用できる:
(display-buffer (get-buffer-create "*foo*") '((display-buffer-below-selected display-buffer-at-bottom) (inhibit-same-window . t) (window-height . fit-window-to-buffer)))
display-buffer-alist
のカスタマイズでは以下のように使用できる:
(setopt display-buffer-alist '(("\\*foo\\*" (display-buffer-below-selected display-buffer-at-bottom) (inhibit-same-window . t) (window-height . fit-window-to-buffer))))
2つ目のバッファーへのカスタマイズを追加するには以下のように記述:
(setopt display-buffer-alist '(("\\*foo\\*" (display-buffer-below-selected display-buffer-at-bottom) (inhibit-same-window . t) (window-height . fit-window-to-buffer)) ("\\*bar\\*" (display-buffer-reuse-window display-buffer-pop-up-frame) (reusable-frames . visible))))
display-buffer-alist
とdisplay-buffer-base-action
はユーザーオプションであって、Lispプログラムはそれらのセットやリバインドを行ってはならない。一方でdisplay-buffer-overriding-action
はアプリケーション用に予約されていて滅多に使用されず、使用する場合には細心の注意を払うこと。
display-buffer
の旧実装では、pop-up-frames
やpop-up-windows
のようなユーザーオプションのセッティングをめぐってユーザーとアプリケーションの競合が頻発した(バッファー表示の追加オプションを参照)。これがdisplay-buffer
を再デザイン(ユーザーおよびアプリケーションにたいして何を行うことが許容されているかを指定する明快なフレームワークを提供する)した主な理由である。
Lispプログラムはユーザーのカスタマイゼーションによって予期せぬ方法でバッファーが表示されるかもしれないことに備えなければならない。display-buffer
の後続の振る舞いにおいてaction引数で要求した方法でバッファーが正確に表示されていると仮定しないこと。
ユーザーは任意のバッファーが表示される方法について厳しすぎる制限を過度に多く設けるべきではない。さもないと特定の目的でバッファーを表示する際の特性を失うリスクがある。横並びの2つのウィンドウでバッファーの異なるバージョンを比較するLispプログラムを記述するとしよう。display-buffer-alist
のカスタマイズによりそのようなすべてのバッファーは常に選択されたウィンドウの下に表示されるように定められていたら、display-buffer
を通じて望ましいウィンドウ構成を構成するのはプログラムにとって困難だろう。
任意のバッファーを表示するための設定を指定するためには、ユーザーはdisplay-buffer-base-action
をカスタマイズする必要がある。複数のフレームで作業を行うことを好むユーザーについての例は前のサブセクションを参照のこと。display-buffer-alist
は特定のバッファーを特定の方法で表示するために予約済みである。
一般的にユーザーとLispプログラムにとって、ウィンドウがすでに対象となるバッファーを表示していて、それを再利用するのは常に良いアイデアである。前のサブセクションではバッファーを表示しているフレームがすでに存在していても、正しく行うことに失敗するとdisplay-buffer
が継続的に新たなフレームをポップアップすることを示した。たとえばバッファーの異なる部分をそのウィンドウで表示する必要がある際のように、少数のケースにおいてはウィンドウの再利用は望ましくないかもしれない。
したがってdisplay-buffer-reuse-window
はaction引数とカスタマイゼーションの両方で可能なかぎり使用するべきアクション関数の1つである。action引数のinhibit-same-window
エントリーは、通常はバッファーをを表示中のウィンドウ、つまり対象となるウィンドウが選択されたウィンドウならそのウィンドウの再利用を避けるような、一般的なケースのほとんどを考慮する。
これは複数フレームで作業を行う人にとっては思考を要しない。バッファーを表示中のフレームは自動的にraiseされてinhibit-switch-frame
が禁じていなければフォーカスを取得する。単一フレームのユーザーにとっては、このタスクは顕著に困難になり得る。この点において特にdisplay-buffer-pop-up-window
とdisplay-buffer-use-some-window
が厄介になる可能性がある。これらは表面上は任意に見えるウィンドウ(最大のウィンドウか最近もっとも使用されていないウィンドウ)を分割または使用してユーザーの注意を逸らす。
したがってLispプログラムのいくつかは、たとえば新たなウィンドウに関して問いに答える場所として期待されるミニバッファーウィンドウの近傍にバッファーを表示するためにフレーム最下のウィンドウの選択を試みる。選択されたウィンドウは通常はすでにユーーザーの注意を喚起済みなので、入力とは無関係なアクションであるdisplay-buffer-below-selected
が好ましいかもしれない。
アプリケーションの多くは引数norecordに非nil
を指定してwith-selected-window
やselect-window
を呼び出すことによって生成されたウィンドウエクスカーション内部からdisplay-buffer
を呼び出す。これはほとんど常に間違った考えである。なぜならそのようなエクスカーション内部で選択されたウィンドウは、ユーザーに提示されているウィンドウ構成で選択されているウィンドウと通常は異なるから。
たとえばユーザーがalistにエントリーinhibit-same-window
を追加していたとすると、そのエントリーによってエクスカーションのスコープ内で選択されたウィンドウを回避するが、結果となる構成において選択されたウィンドウは回避しないだろう。たとえそのようなエントリーが追加されていなくても、結果として奇妙に振る舞うかもしれない。1つの生きたウィンドウを含んだフレームで以下のフォームを評価すると
(progn (split-window) (display-buffer "*Messages*"))
これは他のウィンドウが選択されたまま最下に*Messages*バッファーを表示する。次のフォームを評価すると
(with-selected-window (split-window) (display-buffer "*Messages*"))
これは最上ウィンドウに*Messages*を表示してそれを選択する(display-buffer
の場合は通常は選択しない)。
一方、以下のフォームを評価すると
(progn (split-window) (pop-to-buffer "*Messages*"))
これは*Messages*バッファーを正しく選択するが、次のフォーム
(progn (split-window) (with-selected-window (selected-window) (pop-to-buffer "*Messages*")))
こちらは異なる。
更に選択されたウィンドウの使用時間がすべてのウィンドウの中でもっとも長いことを期待するdisplay-buffer-use-some-window
やdisplay-buffer-use-least-recent-window
のようなアクション関数の呼び出しは、その仕様にしたがったウィンドウの生成に失敗するかもしれない。
したがってウィンドウ
エクスカーションの使用に依存するアプリケーションは、そのエクスカーションが終了するまでdisplay-buffer
の呼び出しの延期を試みるべきである。