Neovim で関数ジャンプする

ある vimmer が IDE を眺めていて思ったこと。

___
### _関数の定義元にジャンプするやつずるい！！！！！！！_
___

__Vim でもぴょんぴょんしたい...__

※ 以下は Neovim での手順ですが、Vim でも Neovim でもだいたい同じ手順のはず

## ctags のインストール

> Ctags（英: Ctags）はソース及びヘッダ内にある名前のインデックス（又はタグ）ファイルを生成するプログラム。
- [Ctags - Wikipedia](https://ja.wikipedia.org/wiki/Ctags)

関数ジャンプを実現するにはこいつと vim のタグジャンプを組み合わせればいい。

ctags といっても exuberant-ctags と universal-ctags というのがあり、前者はメンテされてないっぽい。
なので [universal-ctags](https://github.com/universal-ctags/ctags) をインストールしてみる。  

Mac を使ってるので Homebrew を使う。  

> 
```sh
$ brew install --HEAD universal-ctags/universal-ctags/universal-ctags
```
- [universal-ctags/homebrew-universal-ctags: Homebrew Tap for Universal Ctags on OSX](https://github.com/universal-ctags/homebrew-universal-ctags#usage)

実行が終わったらインストールされたか確認。

```sh
$ brew tap
homebrew/cask
homebrew/core
universal-ctags/universal-ctags
```

追加されてるね。
ついでに `ctags` コマンド打ってみる。

```sh
$ ctags --version
Universal Ctags 0.0.0(ff18000), Copyright (C) 2015 Universal Ctags Team
Universal Ctags is derived from Exuberant Ctags.
Exuberant Ctags 5.8, Copyright (C) 1996-2009 Darren Hiebert
  Compiled: Jul 17 2019, 22:33:32
  URL: https://ctags.io/
  Optional compiled features: +wildcards, +regex, +iconv, +option-directory, +xpath, +case-insensitive-filenames, +packcc
```

たぶんOK。

## 設定ファイルの作成
universal-ctags の設定ファイルは `~/.ctags.d/` 配下に拡張子が `.ctags` のファイルを置く。

```sh
$ mkdir ~/.ctags.d
$ touch ~/.ctags.d/config.ctags
```

`config.ctags` はとりあえず以下のようにしておく。

```ctags:config.ctags
# 除外するファイル or ディレクトリ
--exclude=*.min.js
--exclude=.git
--exclude=node_modules

# タグを作成する言語
--languages=javascript,php,python,typescript

# 言語ごとの作成するタグの種類
--kinds-javascript=*
--kinds-php=-{namespace}{local}{alias}
--kinds-python=*
--kinds-typescript=*

# 再帰的にディレクトリを探索してタグを作成
--recurse=yes

# タグを case-sensitive にソート
--sort=yes

# タグに相対パスを使う
--tag-relative=yes

# 参照する側のタグも作成
--extras=+{reference}
```

### 正規表現を使う
関数名が動的に定義されたりする場合でも、 `---regex-<LANG>=` オプションでタグを作ることができる。
以下は Laravel のスコープとアクセサに対応させた例。

>
```ctags:config.ctags
--regex-php=/get([a-z|A-Z|0-9]+)Attribute/\1/
--regex-php=/scope([a-z|A-Z|0-9]+)/\1/
```
- [LaravelをVimで開発してて、マジックメソッドの定義元にタグジャンプしたい時 - Qiita](https://qiita.com/acro5piano/items/fabf4ac2e410b99a7fab)

## タグの生成
試しにタグを作ってみる。
`-R` は `--recurse` と同じ。

```sh
$ ctags -R
```

デフォルトではカレントディレクトリに `tags` というファイルができる。  
Neovim 経由で作るので一旦削除。

```sh
$ rm ./tags
```

## Neovim の設定
init.vim に追記する。
以下のように書いておくと開いているファイルから親を遡って tags を探してくれるらしい。

>
```vim
set tags=./tags;
```
- [Re: vimの勉強〜タグジャンプの勘どころ〜 - daffy log - 永遠に未完成](https://thinca.hatenablog.com/entry/20090723/1248286959)

他にも色々設定できる。

```vim
set tags=./tags " 開いているファイルのディレクトリから tags を探す
set tags=tags   " カレントディレクトリから tags を探す
set tags=./tags,tags " どちらも探す (優先度高い順)
```

これで、手動で `ctags -R` すれば一応は使えるようになった。  

## プラグイン
ファイル更新時に生成したりするのは面倒なのでプラグイン入れる。
[auto-ctags.vim](https://github.com/soramugi/auto-ctags.vim) が良さそう。

dein などでインストールして、設定を init.vim に追記。  

```vim
" ファイルに書き込む際にタグ生成
let g:auto_ctags = 1
```

Neovim で以下を実行すればカレントディレクトリに tags を生成してくれる。

```vim
:Ctags
```

## 使い方
| コマンド | 動作 |
| --- | --- |
| Ctrl - ] | 定義元にジャンプ |
| Ctrl - t | ジャンプ元に戻る |
| g] | 定義元の候補を列挙する |

## まとめ
結構手間がかかったけど無事に使えるようになった。
関数探すのにいちいち grep しなくて済む！

## 参考
- [Introduced changes — Universal Ctags 0.3.0 documentation](http://docs.ctags.io/en/latest/news.html)
- [Extending ctags with Regex parser (optlib) — Universal Ctags 0.3.0 documentation](http://docs.ctags.io/en/latest/optlib.html)
- [tagsファイルを作成する「auto-ctags.vim」作った - 見方次第](http://soramugi.hateblo.jp/entry/2013/12/01/150433)