vimdiffで単語単位の差分表示: diffchar.vimが超便利

  • 60
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

今日もプログラミングや文書作成にvimを巧みに操り続ける全国のvimmerの皆様におかれましては、vimを利用した差分表示であるvimdiffは欠かせないツールであることと思います。

当方も今までvimdiffについては色を見やすくしたり差分計算アルゴリズムを賢くしたりと、カスタマイズによって使い勝手を向上させてきましたが、唯一実現できていなかったのが、「単語単位の差分表示」なのであります。

しかしついに、vimdiffで単語単位の差分を表示できるようにするvimプラグイン「diffchar.vim」を先日見つけました。最初の公開が今年5月という新しいプラグインです。
diffchar.vim - Highlight the exact differences, based on characters and words : vim online

ということで、早速インストール。このプラグインはGitHubにもミラーされており、すでにNeoBundleをお使いであれば導入はとっても簡単で次の一行を.vimrcに追加して ":NeoBundleInstall" するだけです。それ以外の場合については省略。

~/.vimrc
NeoBundle 'vim-scripts/diffchar.vim'

実際サンプルで試してみましょう。まず、vimdiffで差分を表示させると、次のようになりますね。

スクリーンショット 2014-10-21 17.30.44.png

一つの行に複数箇所の変更が含まれる場合も、最初の変更から最後の変更までを含むような大きな1つの変更として認識されてしまっています。

しかしここで<F7>キーを押すと!

スクリーンショット 2014-10-21 17.32.40.png

うおおおおぉ!すばらしい。単語単位の差分を表示できました。一行に複数の変更があってもちゃんと認識して表示。しかも、追加部分と変更部分で色分けもされています。

ちなみに、再度<F7>キーを押すと元に戻ります。なお、<F7>キーは文書全体について単語単位の差分表示を切り替えますが、<F8>キーを押すと現在の行のみ単語単位の差分表示を切り替えることができます。

これだけでも便利ですが、欲を言えば、vimdiffコマンド実行時やgit diftoolにvimdiffを使っている時に、いちいち<F7>を押すのは面倒。そんな時には、

~/.vimrc
" vimdiffで起動した際自動的に単語単位の差分(diffchar.vim)を有効にする
if &diff
  augroup enable_diffchar
    autocmd!
    autocmd VimEnter * execute "%SDChar"
  augroup END
endif

と.vimrcに書いておけばOK。vimdiffコマンドで起動した時には自動的に単語単位の差分が有効になります。(この場合、単語単位の差分をOFFにしたければ<F7>キーを押す、という使い方になります。)

これでvimdiffで差分をチェックする作業が一層はかどりますね。


※追記(2014/11/20)
diffchar.vimはいくつかのオプションをグローバル変数によって設定することができます。詳しくは公式ドキュメントを参照いただきたいのですが、その中でも特に便利と思われるものをピックアップして紹介します。

g:DiffUnit
単語の境界として認識可能な場所を指定します。デフォルトは"Char"です。
"Char" : 全ての文字間
"Word1" : \w\+ と隣接する \W の境目
"Word2" : 非空白文字と空白文字の境目
"Word3" : \< または \> に該当する境目
"CSV(,)" : カンマ(,)、セミコロン(;)及びタブ文字(\t)による境目

デフォルトの"Char"だと、あらゆる文字間が境界として認識されうるので、変更箇所が変な位置で区切られたりして分かりにくい場合がありますから、そういう場合にはこのオプションを適切に指定します。なお、"Word3"はvimのオプションであるiskeywordの影響を受けます。逆に言えばiskeywordを設定している場合"Word3"を指定すると便利です。

g:DiffUpdate
編集中に差分ハイライトを自動で更新するかどうかを指定します。デフォルトは0(更新しない)です。
0 : 更新しない
1 : 更新する

これらのオプションを.vimrcで指定する場合、プラグインを読み込んだ後(NeoBundleを使っている場合はNeoBundleによるプラグイン指定の後)に指定する必要があることに注意してください。以下は設定例です。

~/.vimrc
let g:DiffUnit = "Word3"
let g:DiffUpdate = 1

※補足:autocmdのイベントはFilterWritePost、BufReadPost 、BufWinEnterなども試しましたが、FilterWritePostでは効果がなく、BufReadPostやBufWinEnterだとどうやらdiff表示途中に実行されてしまうらしく余計な箇所まで単語単位で差分表示しようとしてしまい表示が崩れます。VimEnterを指定したら期待した動作になりました。

自分のブログより転載。(一部をQiita用に修正)