vimでも, タグジャンプを使えるようになりたい!
ということで, vim初心者が, ctagsを導入して, タグジャンプを華麗に(かろうじて)使えるようにするための設定を紹介しようと思います.
環境
OS
OS: Windows 10
Windows Subsystem for Linux (WSL)で, Ubuntu 16.04を動かしています.
vimのバージョン
VIM - Vi IMproved 7.4 (2013 Aug 10, compiled Nov 24 2016 16:44:48)
Included patches: 1-1689
Extra patches: 8.0.0056
ctagsの導入
インストール
自分の環境では, ctags
が, インストールされていなかったです.
$ ctags --version
The program 'ctags' is currently not installed. You can install it by typing:
sudo apt install exuberant-ctags
なので, エラーメッセージの案内に従って, sudo apt install exuberant-ctags
を叩いて, インストールします.
$ sudo apt install exuberant-ctags
exuberant-ctags
は, ctags
の進化版と思っておけば大丈夫でしょう.
ワシントン大学のCS(Computer Science)のctagsの導入の授業のレジュメにも, 無印のctags
じゃなくて, exuberant-ctags
を使えと書いてあります(超意訳).
If you are not on forkbomb or attu, make sure that the system you are using has "Exuberant Ctags" installed, rather than the original "Ctags," by running ctags --version.
ちなみに exuberantは, full of energyとかcheerfulとかという意味なので, まあより使いやすいんだろうなとはイメージできると思います.
インストールしたら, 確認のために,
$ ctags --version
Exuberant Ctags 5.9~svn20110310, Copyright (C) 1996-2009 Darren Hiebert
Addresses: <dhiebert@users.sourceforge.net>, http://ctags.sourceforge.net
Optional compiled features: +wildcards, +regex
ちゃんとインストールされていますね.
tagsファイルの作成
tagsという名前のtxtファイルで, どこに飛ぶかなどを定義しています.
これを作成します.
まず, プロジェクトのルートディレクトリに行きましょう.
今回は, 擬似的にプロジェクトを作成します.
tag_jump_project
というルートディレクトリを作ります.
その中に, src
ディレクトリとlib
ディレクトリを作ります.
$ mkdir -p tag_jump_project/src tag_jump_project/lib
今回は, PHPで書きます.
自分の好きな言語で書けばいいと思います(オブジェクト指向言語がいいかも).
src/tag_jump.php
では, lib/util.php
という名前の関数群を定義したphpファイルからhello
という関数をincludeして, hello()
を呼び出すプログラムです.
<?phpinclude"lib/util.php";hello();
<?phpfunctionhello(){echo"hello",PHP_EOL;}
保存しましょう.
そして, プロジェクトのルートディレクトリ(./tag_jump
)に行きましょう.
そして, ctags -R *
を叩きます.
$ ctags -R *
-R
オプションは, recursively
の意味で, 再帰的にディレクトリをたどって, tagをつけてくれます.
これで, プロジェクトのルートディレクトリ全部のファイルを走査してタグが付きました.
ルートディレクトリに, tags
ファイルがあるので, ルートディレクトリから, vim
を起動しましょう.
自分の場合は, NERDTree
を入れているので, 左側に, ファイラーが出ます.
src
を押して, tag_jump.php
を開いてみましょう.
そして, hello()にカーソルを乗せた状態で, Ctrl + ]
を押しましょう.
Boooon
一瞬で, lib/util.php
のhello
を定義した関数のところに移動しました.
便利なコマンド
ただ, このctagsは, そこまで頭が良くなくて, 継承したクラスファイル先やインポート, インクルードしたファイル先だけでなく, プロジェクトルートにあるファイルを読み込みこんでしまいます.
だから, 同じ名前ものすべてにマッチしてしまいます(インターフェースのメソッドで, そのメソッドの実装がいろんなファイルで, 実装されていると, すべてマッチする. 自動で, 実装先を特定してくれない).
なので, 複数候補がある場合は, 第一候補のページに移ります.
:tn
で, 次の候補, :tp
で前の候補, で移動します.
:ts
で候補を一覧することも可能です.
:ts <tag>
でtag
の名前を検索できます.
この例では, :ts hello
と叩くと, helloが定義されている場所をリスト化してくれます.
そこで選択すると, ジャンプしてくれます.
tsは, tab selectの略です.
tj(ump) <tag>
は, もっと便利で, 候補が複数ある場合だけ, リスト化して, 一つしか候補がない場合は, 直接ジャンプしてくれます.
また, Ctrl + ]
の代わりに, Ctrl + w }
で, プレビュー画面で表示してくれます(水平分割で, 開いていたバッファは, 裏に隠れない).
ほかにも g Ctrl + ]
を叩くと, 候補がある場合, 第一候補ではなく, 候補のリストを表示します.
もっと便利に
tagsファイルは, 新しいメソッドや変数を追加しても, 更新されません.
なので, いちいちctags
コマンドを叩かないと, tagsファイルは更新されず, 新しく定義した関数などは, ジャンプしてくれません.
面倒ですよね?
あります, 自動でtagsを更新してくれるプラグインが.
vim-tags
vim-tagsで, インストールできます.
pathogenが入っている前提でやります.
cd ~/.vim/bundle
git clone https://github.com/szw/vim-tags.git
を叩いて終わりです.
あとはファイルが保存されるごとに, tagsファイルが更新されます.
または, :TagsGenerate
を叩けば, 更新されます.
vimから離れず, tagsファイルを更新できて便利ですね.
便利なマッピング
Ctrl + ]
は, 複数の候補があっても, 第一候補に自動で移動してしまいます.
g Ctrl + ]
を使うと, 候補が一つの場合だけ, 一気に移動して, 候補が複数の場合は, リストを表示してくれます.
なので, マッピングしましょう.
.vimrc
に以下を追加しましょう.
nnoremap <C-]> g<C-]>
ctagsをちゃんと使うからお借りしました.
nnoremapの意味は, 3つに分解して考えるとわかりやすいです.
n NORMAL MODEのマッピング
nore not recursivelyという意味
map mappingするよって意味
not recursivelyというのは, 再帰的じゃないという意味です.
aというキーに, bというキーをマッピングしたとましょう.
またほかの設定で, bというキーに, cというキーをマッピングしてたとします.
recursiveだと, aを押したら, bを意味して, bには, cがマッピングされているから,
aを押したら, cが押されたことを意味します.
これを禁止するのが, noreの意味です.
また, 移動した先に画面がすべて持っていかれるのが嫌!
分割して表示して!という方には,
Ctrl + w }
これは, 第一候補に一気に飛んでしましますし, ts
を叩くとわかりますが, 候補が表示されません.
または,
以下の
nnoremap <C-h> :vsp<CR> :exe("tjump ".expand('<cword>'))<CR>
nnoremap <C-k> :split<CR> :exe("tjump ".expand('<cword>'))<CR>
を.vimrc
に追加するといいでしょう.
Vimスクリプトで軽やかにタグジャンプしようからお借りしました.
<C-h>
と<C-k>
の部分は, 自分の好きなものに変えて大丈夫です.
exe
とかexpand
とか<cword>
とかなんだよって方.
exeは, ()を一度, 変換してから, コマンドを実行します.
tjumpは前回説明したとおりで, は, いまカーソルにいる単語を意味します.
例えば, いま, hello()関数のところにカーソルがあるとします.
すると, expand(<cword>)
は, helloに変わります.
そして, "tjump "と"hello"が.
で結合して, "tjump hello"というコマンドに変わり, 実行されます.
はEnterを意味します.
これで, helloのところに移動します.
ここらへんまで設定できれば, まあまあvimで華麗にジャンプできるんじゃないかなと思います.