Vim で指定したウィンドウに対して任意の設定を行うプラグインをつくった

この記事は Vim Advent Calendar 2012 255日目の記事になります。


以前言っていた popwin.el の Vim 版もどきなんですが、とりあえず形にはなったので公開しようかと思います。
そこそこ汎用性が高くて良い感じなんじゃないかな。
とは言ってもまだ全然使い込んでいないのでバグや改良点はまだまだあると思うんですが…。
設定方法もまだ増えそうだし、quickrun_config のように細かく設定できたほうがいいんだろうか。


そんな感じで人柱大歓迎です。
バグや改良点などがあれば、ぜひ教えてもらえると助かります。

[プラグイン]

NeoBundle "osyo-manga/vim-automatic"

[これはなに]

任意のタイミングで任意の設定を行うためのプラグインです。
例えば、
unite.vim のバッファを開いた時』に『ウィンドウのサイズを変更
したり、
:help のヘルプウィンドウから別のウィンドウに移った時』に『ヘルプウィンドウを閉じる設定
を行ったり、
GUI Vim が起動した後

GUIウィンドウのサイズや位置
などの設定を行うことができます。

[使い方]

g:automatic_config に設定を記述して使用します。

let g:automatic_config = [
\   {
\       "match" : {
\           "filetype" : "help",
\           "buftype" : "help",
\       },
\       "set" : {
\           "height" : "50%",
\           "move" : "bottom",
\       },
\   },
\   {
\       "match" : {
\           "bufname" : '[\[\*]unite[\]\*]',
\           "any_unite_sources" : ['quickfix'],
\       },
\       "set" : {
\           "height" : "30%",
\           "move" : "bottom"
\       }
\   },
\   {
\       "match" : {
\           "autocmds" : ["GUIEnter"],
\           "is_open_other_window" : 0
\       },
\       "set" : {
\           "lines" : 50,
\           "columes" : 150,
\           "winpos_x" : 100,
\           "winpos_y" : 50,
\       },
\   },
\]


g:automatic_config には "match" と "set" をキーに持つ辞書のリストを設定します。


"match" にはどの条件にマッチするか、"set" にはマッチした時の設定を記述します。
g:automatic_config の先頭から順番に "match" をチェックしていき、マッチしたすべての "set" が設定されます。
デフォルトでは autocmd BufWinEnter 時(バッファがウィンドウに表示された後)にチェックを行います。
Vim ではウィンドウが分割された時に処理を hook できないのでこれで代用。
また、チェックするタイミング(autocmd)は "match" の設定で変更することもできます。
"match" や "set" にどんな値が設定できるのかは :help を参照してください。
以下、いくつかの例を上げておきます。

[ヘルプウィンドウを開いた時に大きさや位置を設定する]

" BufWinEnter 時に処理を行う
" &buftype == help であればウィンドウの高さを 20 行にし、
" 一番下で開く
let g:automatic_config = [
\   {
\       "match" : {
\           "filetype" : "help",
\           "buftype" : "help",
\       },
\       "set" : {
\           "move" : "bottom",
\           "height" : 20,
\       },
\   },
\]


また、次のように高さを画面全体の割合で設定することもできます。

" 画面全体の 40% の高さにする
let g:automatic_config = [
\   {
\       "match" : {
\           "filetype" : "help",
\           "buftype" : "help",
\       },
\       "set" : {
\           "move" : "bottom",
\           "height" : "40%",
\       },
\   },
\]

[複数の条件を設定する]

"match" には複数の条件を設定することができます。
複数設定されている場合はすべての条件を満たした時のみ "set" が行われます。

" unite-file が開かれた場合にマッチする
let g:automatic_config = [
\   {
\       "match" : {
\           "bufname" : '[\[\*]unite[\]\*]',
\           "unite_sources" : ['file'],
\       },
\       "set" : {
\           "width" : "30%",
\           "move" : "right",
\       }
\   },
\]

[unite.vim のバッファ名でウィンドウの大きさを変更する]

次のように unite-options-buffer-name で指定した名前でウィンドウの大きさを設定することもできます。

" :Unite -buffer-name=large の場合はウィンドウを大きくする
" :Unite -buffer-name=small の場合はウィンドウを小さくする
let g:automatic_config = [
\   {
\       "match" : {
\           "bufname" : '[\[\*]unite[\]\*]',
\           "unite_bufname" : 'large',
\       },
\       "set" : {
\           "height" : "80%",
\       }
\   },
\   {
\       "match" : {
\           "bufname" : '[\[\*]unite[\]\*]',
\           "unite_bufname" : 'small',
\       },
\       "set" : {
\           "height" : "20%",
\       }
\   },
\]

[別のウィンドウへ移動した場合、そのウィンドウを閉じる]

ウィンドウを開いた後に別のウィンドウへ移動した場合、そのウィンドウを閉じる設定です。

" is_close_focus_out に 1 を設定することで発動
" close_window_cmd にはウィンドウを閉じるコマンドを設定
" デフォルトでは :close を使用する
let g:automatic_config = [
\   {
\       "match" : {
\           "filetype" : "help",
\           "buftype" : "help",
\       },
\       "set" : {
\           "is_close_focus_out" : 1,
\       }
\   },
\   {
\       "match" : {
\           "bufname" : '[\[\*]unite[\]\*]',
\           "unite_sources" : ['file_mru'],
\       },
\       "set" : {
\           "is_close_focus_out" : 1,
\           "close_window_cmd" : 'execute "normal \<Plug>(unite_exit)"'
\       }
\   },
\]

["set" に対してデフォルト値を設定する]

g:automatic_default_set_config を使用することですべての "set" に対してのデフォルト値を設定することができます。

" マッチしたウィンドウの高さをすべて 40 にする
" g:automatic_config に設定されている値が優先される
let g:automatic_default_set_config = { "height" : 40 }

" quickrun のバッファのみ高さを 20 に設定
let g:automatic_config = [
\   {
\       "match" : {
\           "filetype" : 'help',
\           "buftype" : 'help',
\       },
\   },
\   {
\       "match" : {
\           "bufname" : '[\[\*]unite[\]\*]',
\       },
\   },
\   {
\       "match" : {
\           "filetype" : 'quickrun',
\       },
\       "set" : {
\           "height" : 20
\       },
\   },
\]

[gvim の起動時にウィンドウ位置やサイズを設定する]

デフォルトでは BufWinEnter 時に処理が行われるんですが、"autocmds" で任意の autocmd を設定することができます。

" GUIEnter 時にウィンドウのサイズと位置を設定する
" デフォルトではタブページに1つしかウィンドウがない場合はチェックを行わない設
" 定になっているので "is_open_other_window" に 0 を設定して無効にする
let g:automatic_config = [
\   {
\       "match" : {
\           "autocmds" : ["GUIEnter"],
\           "is_open_other_window" : 0
\       },
\       "set" : {
\           "lines" : 50,
\           "columes" : 150,
\           "winpos_x" : 100,
\           "winpos_y" : 50,
\       },
\   },
\]


と、いうような感じで設定して使用することができます。
思ったよりも柔軟性が高そうな感じなのでウィンドウ以外の設定にも使えるんじゃないかな。
処理を行う autocmd もぞれぞれに設定することができるので使い方は色々と広がりそうな感じがします。
そんな感じで面白い使い方とか追加して欲しい機能とか募集中です。