Previous: , Up: 適切なウィンドウへのバッファーの表示   [Contents][Index]


29.13.6 バッファー表示の思想

フレームのもっとも単純な形式では常にバッファー表示に使用可能な単一のウィンドウが収容されています。結果としてdisplay-bufferのもっとも最近の呼び出しは、常にそのウィンドウへのバッファーの配置に成功した呼び出しとなります。

そのようなフレームを処理することは実際的ではないので、デフォルトではEmacsはフレームサイズのデフォルト値、split-height-thresholdsplit-width-thresholdのオプションにより制御される、より複雑なレイアウトを許容しています。そのフレームでまだ表示されていないバッファーを表示すると、フレーム上の単一ウィンドウを分割するか、2つのウィンドウのいずれかを(再)利用します。

これらのしきい値のいずれかをカスタマイズしたり手動でフレームのレイアウトを変更するとデフォルトの動作は棄却されます。非nilaction引数で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-bufferaction関数に使用できる:

(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-alistdisplay-buffer-base-actionはユーザーオプションであって、Lispプログラムはそれらのセットやリバインドを行ってはならない。一方でdisplay-buffer-overriding-actionはアプリケーション用に予約されていて滅多に使用されず、使用する場合には細心の注意を払うこと。

display-bufferの旧実装では、pop-up-framespop-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-windowaction引数とカスタマイゼーションの両方で可能なかぎり使用するべきアクション関数の1つである。action引数のinhibit-same-windowエントリーは、通常はバッファーをを表示中のウィンドウ、つまり対象となるウィンドウが選択されたウィンドウならそのウィンドウの再利用を避けるような、一般的なケースのほとんどを考慮する。

選択したウィンドウにフォーカスを当てる

これは複数フレームで作業を行う人にとっては思考を要しない。バッファーを表示中のフレームは自動的にraiseされてinhibit-switch-frameが禁じていなければフォーカスを取得する。単一フレームのユーザーにとっては、このタスクは顕著に困難になり得る。この点において特にdisplay-buffer-pop-up-windowdisplay-buffer-use-some-windowが厄介になる可能性がある。これらは表面上は任意に見えるウィンドウ(最大のウィンドウか最近もっとも使用されていないウィンドウ)を分割または使用してユーザーの注意を逸らす。

したがってLispプログラムのいくつかは、たとえば新たなウィンドウに関して問いに答える場所として期待されるミニバッファーウィンドウの近傍にバッファーを表示するためにフレーム最下のウィンドウの選択を試みる。選択されたウィンドウは通常はすでにユーーザーの注意を喚起済みなので、入力とは無関係なアクションであるdisplay-buffer-below-selectedが好ましいかもしれない。

どのウィンドウが選択されているのか配慮する

アプリケーションの多くは引数norecordに非nilを指定してwith-selected-windowselect-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-windowdisplay-buffer-use-least-recent-windowのようなアクション関数の呼び出しは、その仕様にしたがったウィンドウの生成に失敗するかもしれない。

したがってウィンドウ エクスカーションの使用に依存するアプリケーションは、そのエクスカーションが終了するまでdisplay-bufferの呼び出しの延期を試みるべきである。