ctag, gtagsで超捗るコードリーディング

vimmerのみなさん初めまして。
vimアドベントカレンダー20日目です。

今回はvimでコードリーディングするのに必須であろうツール、ctagsとgtagsについて設定例も交えながら紹介しようと思います。
色々と導入に手こずった結果、今の自分の環境に沿う形になります。

#補足(2019/09/26)
今であればLSPを導入して、そちらで定義と参照へのジャンプをするのをお勧めします。
https://qiita.com/coil_msp123/items/29de76b035dd28af77a9

#お詫び
macとlinuxの両方でインストールできるようにしたかったのですが、メインマシンのlinux(debian)の方で再現しようとして再インストールしたらgtagsが動かなくなりました...orz助けて(調査します)
仮想環境でのdebianでの再インストール、および新規のubuntuでのインストールはうまくいった。
→どうやら.globalrcを使いまわすとダメっぽい？色々試した結果ダメもとで新しくgtags.confを.globalrcにリネームしてホームに置いたらうまく動いた。

#ctags
ctagsについてはvimについての記事をいくつか読んでいる方なら、既に導入している方も多いと思います。
記事自体はたくさんあるのでサクッと
これがあるとvimのノーマルモードで\<C-]>を押すと、関数やメソッドの定義先に飛ぶことができます。
導入についてはbrewやaptなどで

##追記(18/3/12)
~~何やらバグ？が発生しているようで、jsfaint/gen_tags.vimを使っていると
ctagsを生成するときにエラーが発生する。
↓こんなの↓
<img width="1403" alt="スクリーンショット 2018-03-12 15.26.33.png" src="https://qiita-image-store.s3.amazonaws.com/0/53020/f381ea36-a3bb-e730-36ec-e1bd93a945b1.png">
なんとかならないものかと思ったけどvimscript力が致命的に無くてどうしようもならんかった...orz
どうやらこのままだとctagsの生成ができないらしい。
手動でctagsコマンド打ってタグファイル作って、プラグインの方で呼び出せるように設定を変えれば大丈夫...？~~


~~どうやらexuberant-ctagsではなくuniversal-ctagsが推奨になった？らしい？
universal-ctagsはどうやらhead-onlyらしいので、以下のようにインストール~~


```
$ brew install --HEAD universal-ctags/universal-ctags/universal-ctags
```

~~既にexuberant-ctagsをインストールしている場合は以下のコマンドでアンインストール~~

```
$ brew uninstall --ignore-dependencies ctags
```

~~homebrewを使わない場合は手動でビルドするしかないっぽい。
[この辺](https://qiita.com/k-takata/items/4fba75b66b2cff3a02c7)が参考になるかも~~

~~gtagsの再インストールも必要
ただし、--with-ctagsオプションをつけると、exuberant-ctagsが勝手にインストールされてしまうので~~

```
$ brew install global --with-pygments
```

~~とする。~~

***

##追記(18/3/16)
ctagsのバグ？直ってました。感謝:pray:
***

##追記(18/3/22)
やっぱりexuberant-ctagsじゃなくと動かなくね...?
よくわからん...
***

```
$ brew install ctags
```

```
$ apt install exuberant-ctags
```

とすれば普通に導入できると思います。
実際はapt install ctagsでもexuberant-ctagsを入れてくれます。

これでctagsの導入は完了です。
あとはctagsを使いたいファイルがあるディレクトリで

```
$ ctags　-R
```
と打てばtag情報の入ったファイルが作られるので、あとは実際のファイル上で
定義元の関数、メソッドに飛びたいときに、カーソルを上に置いて\<C-]>を押せば定義元に飛ぶと思います。
ただしこの時、複数の定義があった場合ctagsの方ではどれが正しい関数かは判断できないので、とりあえず一番最初に見つけた定義元に飛んでしまいます。
これ自体は仕方ないのですが、対策としてg\<C-]>とすると定義元が一覧として表示されるのでこちらを使うと良いでしょう。

以上がctagsとなります。これだけでもだいぶコードリーディングが捗ると思います。

#gtags
ctagsだけでもだいぶコードリーディングが捗るとは思うのですが、今一歩物足りない...
というかvscodeをライバル視しているので、ここは是非とも定義元だけでなく参照先にもジャンプしたいところ。
そこで使うのがこちらgtags(gnu globalが正式名称？）

##インストール
###下準備
ctagsに加えpygmentsをインストールする必要があります。

ctagsのインストール
既にインストールしていれば飛ばして大丈夫です。

```
$ brew install ctags
もしくは
$ apt install exuberant-ctags
```

pygmentsのインストール
pygmentsはpythonを使ってパースするツールです。
こちらに依存しているので、まずインストールします。
python2.7の方のpygmentsを使うのでpyenvかなんかを使っている人はpython2.7も動くようにしてください。

```
pip install pygments
インストール後
pygmentize
コマンドが動くはずです。
```

上記二つインストールが完了したらgtagsをインストールします。
パッケージ名はglobalなので

###gnu global

```
$ brew install global
もしくは
$ apt install global
```

注意点としてgnu globalのバージョンは6以上を想定しているので、バージョン5などがインストールされてしまう場合は、自分でビルドしてみてください。
[参考](https://qiita.com/akegashi/items/042c659c856d2092c443)
環境を汚したくない場合は、別途ホームディレクトリなどにoptフォルダなどを作り、パスを作ってそこにインストールすることをおすすめします。

これで、globalコマンド及びgtagsコマンドが動くようになります。
これらはターミナル上でも使えます。
ただし、gnu globalはそのままだとpythonやrubyなどに対応していない、すなわちpygmentsを呼び出さないため、明示的にコマンドで指定するか、.globalrcというファイルをホームに配置する必要があります。

.globalrcはインストールしたgtagsのフォルダ、もしくはビルドに使ったgnu globalのフォルダに入っているgtags.confをリネームしてください。
自分のdotfilesの中に入っているものですがこのような中身のファイルです。
https://raw.githubusercontent.com/coil398/dotfiles/master/.globalrc

自分で用意した場合は、gtags.conf及び.globalrcの中に

```
default:\
	:tc=native:tc=pygments:
```

といった部分がファイルの上の方に有るので

```
default:\
	:tc=native:tc=pygments:
```

このように書き換えてください。
これで通常のようにgtagsを実行するとpygmentsを使ってくれるようになります。

試しに適当なフォルダで

```
$ gtags -v --debug
```

というコマンドを打つと(-vはverboseオプション、--debugはそのままデバグ用？のオプション。どちらもなくても可)
するとGTAGS, GPATH, GRTAGSといったファイルが出来ていると思います。
この中にgtags用のデータが入っています。

試しに

```
$ global -f [file]
```

を実行すると、そのファイルに含まれる関数などの一覧が表示されます。

###vim上でgnu globalを使う(便利なプラグイン)

では、これをvim上で使ってみましょう。
まず、先程の.globalrcのようにgtags.vimファイルが有ると思います。
これをvim上で読み込めば良いのですが、もしプラグインマネージャを利用しているのであれば、githubのレポジトリに公開してくださっている方がいらっしゃるのでこちらを利用することをおすすめします。

```
lighttiger2505/gtags.vim
```

参考https://qiita.com/lighttiger2505@github/items/6b1cd3bc79cb9806a743

これでvim上でgnu globalを使う準備ができましたので、実際に使っているキーマッピングを紹介します。

```
nnoremap <silent> <Space>f :Gtags -f %<CR>
nnoremap <silent> <Space>j :GtagsCursor<CR>
nnoremap <silent> <Space>d :<C-u>exe('Gtags '.expand('<cword>'))<CR>
nnoremap <silent> <Space>r :<C-u>exe('Gtags -r '.expand('<cword>'))<CR>
```

コマンドでのglobalと同じように使えます。

<Space>fで今のファイルの関数などの一覧
<Space>jでカーソル下の単語が含まれるタグの表示
<Space>dでカーソル下の単語の定義元を表示
<Space>rでカーソル下の単語の参照先を表示
いずれもQuickFixで表示されるため、QuickFix関連のキーマッピングを設定しておくとはかどります。

次に、おすすめのプラグインとしてgen_tags.vimを紹介します。
これはターミナル上でのctagsやgtagsの生成やそれらの自動化をしてくれるプラグインです。

```
jsfaint/gen_tags.vim
```

これもプラグインマネージャがあれば、そちらでインストールするのをおすすめします。
インストールしたら

```
let g:gen_tags#ctags_auto_gen = 1
let g:gen_tags#gtags_auto_gen = 1
```

と設定すると、自動でctags, gtagsを生成、更新してくれます。
ただし、ディレクトリにあるgitなどのSCMを参考にタグの生成を行うので、それらを用意する必要があります。
自動生成と更新は恐らくファイルの保存をした際に行われるようです。

一つ注意点として、自分もハマってしまったのですが、デフォルトでキャッシュを使う設定になるので
vim上で、生成したtagsファイルは、ホームの.cacheフォルダに有るtags_dirフォルダに格納され、そちらが参照されるようになります。
ターミナル上でglobalコマンドを使用する際には支障はありませんが、vim上でglobalコマンドやgtagsコマンドを使用した際は問答無用でそちらが参照されてしまうので、ターミナル上でgtagsを使ってGPATH, GTAGS, GRTAGSファイルを生成してもvim上でそれらを参照することはできないことに注意してください。
詳しくはhttps://github.com/jsfaint/gen_tags.vim を参照してください。

他にもdenite(unite)用のソースファイルもあるのですが、自分は基本的に使っていないのでそちらについては割愛させていただきます。

#結論
めっちゃ捗る

#最後に
遅くなってしまって申し訳ありませんでした。
ちょっと急いで書き上げてしまったのでわかりにくい部分があるかもしれません。というか自分も何故か結構苦労したので何かしら質問があればコメントお願いします。