ヘルプバッファや補完バッファをポップアップで表示してくれるpopwin.elをリリースしました

ヘルプバッファや補完バッファをポップアップで表示してくれるpopwin.elをリリースしました。popwin.elはEmacsにポップアップウィンドウという概念を導入することにより、バッファを表示する(display-buffer)際のEmacsのトチ狂った仕様を矯正します。この「トチ狂った仕様」とは例えば、

  • M-x describe-functionしたらウィンドウが勝手に分割された
  • あるいはウィンドウのバッファを勝手に切り替えられた
  • ヘルプバッファ(*Help*)とか補完バッファ(*Completions*)がどのウィンドウに出現するか予測できない
  • しかも作業後にそれらのバッファが表示されたままになったりする

のようなものを指します。Emacsを触ったことがある人なら上記のいずれかは不満に思ったことがあるはずです。ちなみに僕は全てを不満に思っています。

余談になりますが、Wikipedia学習性無力感によると、長期間のストレスは、その対象にある種の無力感を与えるらしいです(犬に電気ショックを与える実験によりこの学習性無力感を実証した)。Emacsユーザーもこの実験の犬と同じなのではないでしょうか。つまり、この謎仕様に少なからずストレスを感じているのにもかかわらず、そのストレスがあまりに長期間であるため対抗する気概が失なわれているのではないかと。かくいう僕もその状態だったわけですが、重い腰をあげて全力で対抗してやりました。その結果生まれたのがpopwin.elなのです。不満に思いはじめてからおよそ4年が経過していました。

本題に戻って、popwin.elのポップアップウィンドウがどういうものかを説明しておきましょう。ポップアップウィンドウというと小さなウィンドウがポンと出てくるイメージがありますが、ここでのポップアップウィンドウは、あくまでEmacsにおける「ウィンドウ」であって、フレームの4辺からウィンドウを引き出すように表示されます。

ポップアップ前

ポップアップ後(補完バッファを表示)

popwin.elはこのポップアップウィンドウをベースにして、上記の問題の解決するための優れたユーザーインターフェースを提供します。

インストール

popwin.elを下記からダウンロードしてロードパスの通ったディレクトリにインストールしてください。

https://github.com/m2ym/popwin-el

install-elispやauto-installを持っている人は次のようにインストールすることも可能です。

;; install-elisp
(install-elisp "https://github.com/m2ym/popwin-el/raw/master/popwin.el")
;; auto-install
(auto-install-from-url "https://github.com/m2ym/popwin-el/raw/master/popwin.el")

最後に.emacsに次の初期化コードを書いてください。

(require 'popwin)
(setq display-buffer-function 'popwin:display-buffer)

display-buffer-functionを変更したくない人は次の初期化コードでも動作します。

(require 'popwin)
(setq special-display-function 'popwin:special-display-popup-window)

ただし、あらかじめspecial-display-buffer-namesあるいはspecial-display-regexpsにポップアップ表示したいバッファを設定しておく必要があります。

使い方

デフォルトでは*Help*, *Completions*, *compilatoin*, *Occur*バッファがポップアップ表示されます。試しにM-x find-fileしてTABを数回押してみてください。フレーム下部に*Completions*バッファがポップアップ表示されると思います。

補完バッファのポップアップ表示

他のウィンドウを選択するか、C-gすることによりポップアップウィンドウを閉じることができます。もちろん元のウィンドウの状態は保持されます。

他の例のスクリーンショットも示します。

M-x occur

M-x compile

設定

ポップアップウィンドウの幅や高さはpopwin:popup-window-widthやpopwin:popup-window-heightで設定します。ポップアップウィンドウの表示される場所はpopwin:popup-window-positionで設定します。値はleft, top, right, bottomのいずれかです。

どのバッファをポップアップ表示するかはpopwin:special-display-configで制御します。この変数には(pattern :regexp VAL :width VAL :height VAL :position VAL :noselect VAL)の形をした値のリストが入ります。patternには、ポップアップ表示するバッファ名を文字列を指定します。patternにシンボルを指定するとそのメジャーモードのバッファがポップアップ表示されます。

例えば以下のコードは*scratch*バッファをポップアップ表示します。

(setq popwin:special-display-config '(("*scratch*")))
(display-buffer "*scratch*")

:regexキーワードにtを指定するとpatternに正規表現を指定できます。:widthキーワードに値を設定するとpopwin:popup-window-widthの代わりにこの値が使用されます。:heightキーワードや:positionキーワードも同様です。:noselectキーワードにtを指定するとポップアップ表示時にポップアップウィンドウを選択しません。

popwin.elはあくまでdisplay-bufferを制御するものですので、バッファの切り替えなどはその対象外です。例えば先の*scratch*バッファの設定を行ったあとにswitch-to-bufferしてもポップアップ表示されません。これはバグでなく仕様です。

設定例:Anything

*anything*バッファをポップアップ表示する設定です。

(setq anything-samewindow nil)
(push '("*anything*" :height 20) popwin:special-display-config)

*anything*バッファをポップアップ表示

設定例: Dired

diredのバッファをフレームの上部にポップアップ表示する設定です。

(push '(dired-mode :position top) popwin:special-display-config)

(require 'dired-x)してからM-x dired-jump-other-windowするとdiredのバッファをポップアップ表示できます。

diredのバッファをポップアップ表示

API

基本的なAPIを紹介します。詳しくはソースコードは読んでください。

popwin:create-popup-window &optional size position adjust => (master-window popup-window)

popwin:create-popup-windowはポップアップウィンドウを作成して、マスタウィンドウと共に返します。マスタウィンドウとはポップアップウィンドウを作成するために分割されたウィンドウです。ポップアップウィンドウを閉じる作業は開発者の責任です。

popwin:popup-buffer buffer &key width height position noselect => popup-window

popwin:popup-bufferはバッファbufferをポップアップウィンドウで表示します。ポップアップウィンドウは自動的に閉じられます。キーワードで渡す引数の意味はpopwin:special-display-configのものと同じです。

popwin:display-buffer buffer flag => window

popwin:display-bufferはpopwin:special-display-configを参照することにより、バッファbufferをポップアップ表示すべきかどうか調べて、ポップアップ表示すべきならそのバッファ特有の設定でpopwin:popup-bufferを呼び出します。ポップアップ表示すべきでないなら、通常通りdisplay-bufferします。

まとめ

popwin.elは地味ですが、Emacsの根本的なユーザーインターフェースの問題を解決してくれます。まだ安定していないと思いますので、どんどん使ってバグ報告してください。メールならtomo@cx4a.orgに、twitterなら@m2ymにメッセージくれると嬉しいです。それでは。