やばいやばい、VACの執筆予定日がもっと後だと思っていて、穴をあけてしまいました・・・本当に申し訳ないです。
今後はitchyny/calendar.vimで予定を角煮するようにします。
unite-include-reversedというunite sourceとしてのVim pluginの実装を先日開始しました。(*1)
このプラギンは背景を説明するのが難しいと考え、そのために専用の記事を設けることにしました。それがこの記事です。
C言語に#include
、Clojureにimport/require/use
、Haskellにimport
、Rubyにrequire
など、各プログラミング用語ごとに「他のファイルから何かをもってくる」という機能が存在します。ここではこれらすべてを総称してincludeと呼ぶことにしましょう。
Vimはincludeに対する様々な機能を提供しています。
[I
(後述)<C-x><C-i>
(insert mode) によるインクルード補完- neocomplete利用で自動化
:NeoCompleteIncludeMakeCache
でキャッシュ作成
gf
(include専用ではないけど):checkpath!
includeしてるファイルを再帰的に網羅
[I Display all lines that contain the keyword under the
cursor. Filenames and line numbers are displayed
for the found lines. The search starts at the
beginning of the file. {not in Vi}
試しに以下のようなコードを書き、:checkpath!
してみましょう。
a.c (保存する必要はありません)
#include <stdio.h>
int main(int argc, char const* argv[])
{
puts("hello, world!");
return 0;
}
:checkpath!
stdio.h
とその依存先をすべて検索していることがわかります。
つづいて先ほどのputs
のところにカーソルを移動し、[I
と打鍵しましょう。
いまC言語で試しましたが、他のfiletypeでも正しく設定が行われていれば利用できます。
設定はftpluginで行います。たとえばscalaのためのプラギンvim-scalaでは、Scalaのimport
文に対してVimのincludeに関する諸機能が利用可能になります。(*2)
https://github.com/derekwyatt/vim-scala/blob/master/ftplugin/scala.vim#L2
ちょっと名前と機能で整理してみましょう。
:checkpath!
- そのファイル内でincludeしてるものすべてを一欄する。再帰的にincludeをたどりつづけて木にする。
[i
- カーソル位置のidentifierが最初に定義された行を表示。include先も辿る。
[I
- カーソル位置のidentifierが登場するすべての行をファイル名とともに表示。include先も辿る。
gf
- カーソル位置がincludeのpathっぽいもののとき、そのファイルそのものを開く
ところで著者は以下のような機能も欲しいです。
???
- 「カーソル位置がincludeのとき、そのincludeからもってきたidentifierを使っている行をすべて表示する。include先を辿らない」
つまり、前述の4つを順引とみたときの、逆引きが欲しいのです。
この逆引き機能は、ざっと考えてみたところ、以下のようにして実現できそうです。
:checkpath!
などで、includeしているファイル一覧を先に生成しておく- ファイル先頭からidentifier単位で移動し、各identifier上で
[I
し、includeしているファイル名を辞書に保持する - 最後まで探索が終わったところで、その辞書をもとに、includeしているファイル名からidentifierを一覧する。
副作用のかたまりですね。
これはあきらかにuniteのsourceにするのがよさそうな例です。 というわけでプラギン名はuniteのsourceでかつincludeを逆引きするもの、つまりunite-include-reversedという名前にしました。
レポジトリはありますが、まだ動作するレベルにはなっていません。 https://github.com/ujihisa/unite-include-reversed
これを実装するために、vital.vimに[I
を関数として使えるようにした Vim.Search.finddef()
を実装しました。
これを用いると[I
の結果のようなものをパースした辞書が得られます。
- *1 諸事情であれからずっと停滞しています。やばい
- *2 この設定はujihisaさんがpullreqしました。
- *3 インクルード補完とそのための設定について詳しくはコチラも参照のこと http://d.hatena.ne.jp/thinca/20091026/1256569191