今日もプログラミングや文書作成にvimを巧みに操り続ける全国のvimmerの皆様におかれましては、vimを利用した差分表示であるvimdiffは欠かせないツールであることと思います。
当方も今までvimdiffについては色を見やすくしたり差分計算アルゴリズムを賢くしたりと、カスタマイズによって使い勝手を向上させてきましたが、唯一実現できていなかったのが、「単語単位の差分表示」なのであります。
しかしついに、vimdiffで単語単位の差分を表示できるようにするvimプラグイン「diffchar.vim」を先日見つけました。
最初の公開が今年5月という新しいプラグインです。
diffchar.vim - Highlight the exact differences, based on characters and words : vim online
ということで、早速インストール。このプラグインはGitHubにもミラーされており、
2019/01/07 追記: 現在、こちらで開発が続けらているようです。
https://github.com/rickhowe/diffchar.vim
すでにNeoBundleやdeinをお使いであれば導入はとっても簡単で一行.vimrcに追加して :NeoBundleInstall
や call dein#update()
するだけです。
" NeoBundleの場合
NeoBundle 'rickhowe/diffchar.vim'
" deinの場合 `if dein#load_state(path)` 〜 `endif` の間に
call dein#add('rickhowe/diffchar.vim')
実際サンプルで試してみましょう。まず、diffchar.vim導入前、vimdiffで差分を表示させると、次のようになりますね。
一つの行に複数箇所の変更が含まれる場合も、最初の変更から最後の変更までを含むような大きな1つの変更として認識されてしまっています。
しかしdiffchar.vimを導入すると!
うおおおおぉ!すばらしい。単語単位の差分を表示できました。一行に複数の変更があってもちゃんと認識して表示。しかも、追加部分と変更部分で色分けもされています。
なお、以前は<F7>キーで単語単位の差分表示を切り替えるようになっていましたが、diffchar.vim Ver5.5以降、vimdiffコマンドによるvim起動時にはデフォルトで自動的に単語単位の差分表示が有効化されるようになりました(この動作は g:DiffModeSync
により切替可能です)。
これでvimdiffで差分をチェックする作業が一層はかどりますね。
※追記(2014/11/20)
diffchar.vimはいくつかのオプションをグローバル変数によって設定することができます。詳しくは公式ドキュメントを参照いただきたいのですが、その中でも特に便利と思われるものをピックアップして紹介します。
g:DiffUnit
単語の境界として認識可能な場所を指定します。デフォルトは"Char"です。
"Char" : 全ての文字間
"Word1" : \w\+ と隣接する \W の境目
"Word2" : 非空白文字と空白文字の境目
"Word3" : \< または \\> に該当する境目
"CSV(,)" : カンマ(,)、セミコロン(;)及びタブ文字(\t)による境目
デフォルトの"Char"だと、あらゆる文字間が境界として認識されうるので、変更箇所が変な位置で区切られたりして分かりにくい場合がありますから、そういう場合にはこのオプションを適切に指定します。なお、"Word3"はvimのオプションであるiskeywordの影響を受けます。逆に言えばiskeywordを設定している場合"Word3"を指定すると便利です。
g:DiffModeSync
この設定が"1"の場合、vimdiffコマンドによる起動などによりdiffモードが有効になった際、単語単位の差分表示も連動して有効にします。デフォルトは"1"です。
なお、単語単位の差分表示の有効・無効を手動で切り替えたい場合は<F7>キーを使います。
これらのオプションを.vimrcで指定する場合、プラグインを読み込んだ後(NeoBundleを使っている場合はNeoBundleによるプラグイン指定の後)に指定する必要があることに注意してください。以下は設定例です。
let g:DiffUnit = "Word3"
※2019/01/07 : 本文および追記の内容を最新の状況に合わせて修正しました
※補足:autocmdのイベントはFilterWritePost、BufReadPost 、BufWinEnterなども試しましたが、FilterWritePostでは効果がなく、BufReadPostやBufWinEnterだとどうやらdiff表示途中に実行されてしまうらしく余計な箇所まで単語単位で差分表示しようとしてしまい表示が崩れます。VimEnterを指定したら期待した動作になりました。
※自分のブログより転載。(一部をQiita用に修正)