読者です 読者をやめる 読者になる 読者になる

Vimの+diff機能の仕組みについて

Vim

ばよえ〜ん(訳:Vim Advent Calendar 2012への14回目の投稿です)
この記事はVim Advent Calendar 2012の137日目の記事になります。
136日目は@alpaca_taichouさんでpowerlineをいつ使う?今でしょ!でした。


Vimの+diff機能の仕組みについて、と言いつつそこまで詳細について解説している訳ではないです。
差分のアルゴリズムとかそういうのを期待している人はすみません。*1

スクロールを異なるウインドウ間で同期させる ('scrollbind')

'scrollbind'オプションを使います。
'scrollbind'オプションが有効になっているウインドウでスクロールすると、
他の'scrollbind'オプションが有効になっているウインドウもスクロールされます。
スクロールの同期をやめるには'scrollbind'オプションを無効にします。


ちなみに'scrollbind'オプションはスクロールを行ったら他のウインドウもスクロールさせるという性質上、内容までは見ていません。
そのため内容が違う行が入っていたり削除されていたりすると、段々とずれてきてしまいます。
そのため、で現在のウインドウのスクロールのみ調整できるようにしています。


'scrollbind'は便利ですが、内容までは考慮しないため、比較する場合にはもっと便利な機能がVimにはあります。
次の項目の:diffsplitを使ってください。*2

参考

:help 'scrollbind'
:help scroll-binding

:diffsplit

さて、前述の'scrollbind'オプションは内容までは考慮しないため見ている位置がずれてくるという欠点がありました。
また、スクロールの同期もいいけど、似たような文書なら普通diffしたいと考えるのではないでしょうか?
Vimにはもちろんdiff機能が備わっています。:diffsplitです。
その機能の強力さは他のdiffツールの中でもトップクラスと言えるのではないでしょうか。
ちなみにUnix系でvimをインストールするとvimdiffというコマンドもインストールされますが、これは:diffsplitを使っています。

参考
  • :help :diffsplit
  • :help diff

カーソル位置を異なるウインドウ間で同期させる ('cursorbind')

このオプションはVim 7.3で追加された比較的新しいオプションです。
しかしその機能は、'scrollbind'はスクロール位置(ウインドウに表示されているバッファの位置)を保持するのに対し、'cursorbind'は「カーソル位置を保持する」という地味なオプションです。


diff時はこの'cursorbind'を自動的にセットします。
diff時は平行して操作することが多いため、ウインドウを移った時は同じような位置にカーソルがセットされていると(地味ですが)便利だからです。
'scrollbind', 'cursorbind'だけではなくいくつかのオプションがセットされます。

(:help diff から引用)

	'diff'		on
	'scrollbind'	on
	'cursorbind'	on
	'scrollopt'	"hor" を入れる
	'wrap'		off
	'foldmethod'	"diff"
	'foldcolumn'	2

例えば、'scrollbind', 'cursorbind'はすでに解説しましたが、'foldmethod'は変更されていない箇所を折り畳んで表示しないためにあります。


またVimのdiff機能は自身で差分を計算している訳ではなく、
'diffexpr'オプションで指定された差分を出力するプログラムを使用しています。
値が空の時はdiffコマンドが指定されたものとみなします。
そのためWindows環境でdiffコマンドがPATHに入っていないと「E97: Cannot create diffs」と言われdiff機能は使えません。


このようにdiff機能に限らず、Vimの機能はいろんなオプション/外部コマンドの組み合わせで実現されています。

*1:この記事でも言ってますが、そもそもVimは自分で差分を計算している訳ではないので

*2:もちろん'scrollbind'が:diffsplitより使えないとか言ってる訳じゃなく、もっと別の使い道があるはず