Vim Advent Calendar 2013 の 114 日目の記事です。
gf の問題について
gf は、カーソル下のファイルを開く便利機能です。例えば、"foo.c" とバッファに書かれていた場合、ここにカーソルをのせて gf を押すと、foo.c を開いてくれます。更に gF を使うと、"foo.c:23" みたいになっていた場合に、foo.c の 23 行目を開いてくれるので、更に便利です。
便利なんですが、これ、Windows だとうまく動きません。なぜかと言うと、Windows では 'isfname' に : が含まれているから。
'isfname' は、ファイル名として認識する文字のセットを指定するオプションで、gf はこれを使ってカーソル位置のファイルを認識します。しかし Windows ではドライブレター(C:とか)の関係で : が isfname に含まれているため、foo.c:23 全体をファイル名として認識してしまい、結果としてファイルを開くことができません。
この問題について、本体を修正する動きもありますが、いつ入るか、そもそも入るのかがわかりません。それが待てない場合、プラグインで解決するしかなさそうです。
gf-user
gf-user は、gf の動作を拡張するためのフレームワークです。textobj-user や operator-user を作った kana さん謹製です。
https://github.com/kana/vim-gf-user
gf には gF も含めて派生のキーマッピングがいくつかあり、全部対応しようとすると大変です。このフレームワークを使えば、関数を1つ定義するだけで簡単に対応可能です。
それでは、上記の問題を解決すべく、設定を書いてみましょう。
ちなみに gf-user の help では、拡張を書く際は autoload 関数にして gf#{ext}#find と言う名前にすべきとありますが、今回は vimrc に直接書いてしまいます。
function! GfFile() let path = expand('<cfile>') let line = 0 if path =~# ':\d\+:\?$' let line = matchstr(path, '\d\+:\?$') let path = matchstr(path, '.*\ze:\d\+:\?$') endif if !filereadable(path) return 0 endif return { \ 'path': path, \ 'line': line, \ 'col': 0, \ } endfunction call gf#user#extend('GfFile', 1000)
expand('
これで無事、Windows でもジャンプできるようになりました。
ちなみに既存の拡張として、gf-diff があります。これは diff 上で gf すると、その差分のオリジナルのファイルにジャンプできます。非常に便利です。
余談 - 更なる問題
ところで、gf で開く時に、微妙に上位層も見てくれると便利そうです。
例えば、カレントディレクトリが /foo/project/src だったとして、カーソルが、"src/hoge.c" と言うテキストの上にあった場合、通常なら gf すると /foo/project/src/src/hoge.c を探してしまって見付からないのですが、ここは気を利かせて /foo/project/src/hoge.c を開いて欲しいですよね。
先程の設定に1行追加します。
function! GfFile() let path = expand('<cfile>') let line = 0 if path =~# ':\d\+:\?$' let line = matchstr(path, '\d\+:\?$') let path = matchstr(path, '.*\ze:\d\+:\?$') endif let path = findfile(path, getcwd() . ';') " 追加 if !filereadable(path) return 0 endif return { \ 'path': path, \ 'line': line, \ 'col': 0, \ } endfunction call gf#user#extend('GfFile', 1000)
これで無事、上の階層にあるファイルも開けそうです。
これらの機能は便利なので、プラグイン化して配布したいところなのですが、ここで問題が出てきます。
「Windows で foo.c:23 に対応する機能」と、「上の階層を見にいく機能」は、どう考えても別物の機能なので、1つのプラグインに入れるのは不自然です。しかし、これらを別々のプラグインとして提供してしまうと、「上の階層を見に行きつつ foo.c:23 を Windows で開く」と言ったことができなくなってしまいます。
現状ではどうしようもなさそうなので私は vimrc に書いてしまっていますが、今後こういうのも可能になってくると更に便利になりそうです。