なにかと誤解が非常に多いVimのfiletype pluginについての解説。VimM#2でfiletype pluginについてスルーしたのは、以下の分量から察してください。
Vimはバッファ毎にその内容の種類、例えばPerl/Python/Rubyスクリプトといった情報が保持されており、それは'filetype'というオプションで表される。Filetype pluginとは'filetype'に応じた機能を提供するためのスクリプトである。その性質上、提供される機能はバッファローカルである。
Vimは標準で多数のfiletype pluginが同梱されている。どのようなものがあるかはVim内で:edit $VIMRUNTIME/ftplugin/を実行してみれば分かる。:help ft-filetype-pluginで'filetype'に対するfiletype pluginのドキュメントが読める。標準添付されているfiletype pluginの多数はいくつかのオプションを設定するだけであるため、敢えてドキュメントがないものが多い。
Vimのfiletype pluginはEmacsで言えばmajor modeや一部のminor modeに近い存在である。あくまで近いのであって、同じものではないことに注意。
各filetype pluginは'runtimepath'のftplugin/ディレクトリ下に配置される。例えばVimに標準添付されているfiletype pluginは全て$VIMRUNTIME/ftplugin/下にある。
自分で独自のfiletype pluginを作成・使用する場合、'runtimepath'に記述されている最初のディレクトリ下のftplugin/ディレクトリにファイルをコピーする('runtimepath'のデフォルト値であれば~/.vim/ftplugin/などである。この値は環境により異なり、また'runtimepath'を変更してる場合はこの限りではない)。場合によってはftplugin/ではなくafter/ftplugin/下にコピーする必要がある(詳細は後述)。
Filetype pluginのファイル名は次の3つのいずれかに合致しなければならない:
filetype.vimfiletype_frag.vimfiletype/frag.vimここでfiletypeはそのfiletype pluginが適用されるべき'filetype'の値と同じ文字列であり、fragは任意の文字列である。fragを含む形式は、同一'filetype'に対して複数のfiletype pluginを用いたい場合のために用意されている。例えばpython/smartchr.vimにはsmartchrを利用した設定を記述しておき、python/textobj.vimに独自のtext objectsに関する定義を記述するなどが考えられる。
Filetype pluginはファイルが開かれた場合などのイベントに応じて自動的にロード(:source)される。具体的にはFileTypeが発生したときにロードされ、FileTypeが発生する条件は以下の通りである:
:setfiletypeなどによる手動'filetype'設定BufEnter、BufNewFile、BufRead、StdinReadPostのいずれかのイベントの発生(ただし'filetype'によって用いられるイベントは微妙に異なる)Filetype pluginは'runtimepath'に記述されたディレクトリから順々に該当するファイルがロードされる。同一ディレクトリ下のファイルに関しては次の順番でロードされる:
filetype.vimfiletype_frag.vimfiletype/frag.vim後者2つについてはfragの辞書式順序でロードされる。
:setlocalを使用する。詳細: Vim: オプションのグローバルな値とローカルな値<buffer>を指定する。詳細: Vim: Key mappingを極める-bufferを指定する。b:varを使う。:bwipeoutによって完全に削除される可能性があることに注意する。また、:bdeleteでは削除されないということにも注意する。b:did_ftpluginによる無効化:editによるバッファ内容のリロード時などによる複数回のロードを抑止したいケース)のため、filetype pluginの冒頭で以下のような記述をする:if exists('b:did_ftplugin')
finish
endif
let b:did_ftplugin = 1このチェック用変数名はb:did_ftpluginでなければならない。b:undo_ftpluginに設定のリセット情報を記述する:setlocal expandtabをするならば、:let b:undo_ftplugin = 'setlocal expandtab<'のようにし、設定した事項をリセットするためのVim scriptコードを文字列としてセットする。g:maplocalleaderでユーザー側が任意に選択できる。ここでは説明のために以下の用語を用いる:
ftplugin/に配置されるfiletype plugin。after/ftplugin/に配置されるfiletype plugin。~/.vim/'runtimepath'のデフォルト値の先頭にあるディレクトリ。具体的な値は環境によって異なる。Filetype pluginを書く場合、どういう目的で書くかによって書き方が異なる。具体的な目的は以下の3つである:
'filetype'についてのfiletype pluginを書きたい~/.vim/ftplugin/が望ましい。~/.vim/ftplugin/にする。b:did_ftpluginを定義し、標準添付のfiletype pluginがロードされることを抑止する。~/.vim/after/ftplugin/にする。b:did_ftpluginのチェックとセットは行わない。何故なら標準添付のfiletype pluginが既にロード済みであるため、必ずb:did_ftpluginは存在し、結果として常にロードが抑止されることになるからだ。同様に他のadditional filetype pluginsに影響が出るため、セットもしてはならない。b:did_ftpluginと同様のチェックは必要である。この場合、b:did_ftplugin_filetype_fragなどの変数を使い、b:did_ftpluginを使ってはならない。b:undo_ftpluginの設定など。それについては後々公開する予定。'filetype'は複数の値を設定できる。例えば:setfiletype c.doxygenなどとピリオドで区切った名前の列によって複数の値を持たせることができる。個人的には、複数の値を持つ場合は「compound filetype」、通常の値の場合は「simple filetype」と呼び分けている。'filetype'がc.doxygenの場合、まずc用のものがロードされ、その後でdoxygen用のものがロードされる。b:did_ftpluginの関係上、活用できないと言っても過言ではない状態である。この辺りもどうにかしたいところ