Vimのdiffモード機能はVimを使うべき一つの大きな理由になるくらい便利なものだと思います。
違いを見るためだけでも左右に並べて見れるので
diff
コマンドなんかよりもよりわかりやすく見ることが出来ます。
そのdiffモード関連のVimの機能やプラグイン等のまとめ。
- vim -d
- vimdiff
- :diffsplit
- diffモードでの操作
- diffモードの設定
- :DiffOrig
- linediff.vim
- vcscommand.vim
- diffchar.vim
- vim-diff-enhanced
vim -d
2つの似たようなファイルを比べたい時に
$ vim -d a.txt b.txt
とすると2つを比べた状態でファイルを開くことが出来ます。
3つ以上同時に比較することも可能です。
diffモードでは以下のオプションがセットされます。
diff
: on, diffモードであるかどうかの指標。scrollbind
: on, 比べてる2つのウィンドウのスクロールを同期。cursorbind
: on, 比べてる2つのウィンドウのカーソル位置を同期。scrollopt
: includes “hor”,scrollbind
の方法。”hor”(horizontal)で水平方向のスクロールを同期。 元々デフォルトで”ver”(vertical)オプションが入っているので通常縦方向も同期する。wrap
: off, 一行が長い時に折り返しをしない様にする。折り返しをすると左右で同期している時に表示が崩れてしまう事があるので一応offが推奨。foldmethod
: “diff”, 畳み込みの方法。”diff”は違いがある付近のみを残して畳み込む様にする。foldcolumn
: value from ‘diffopt’, default is 2, 左側に示すdiffの状況表示の幅。
Vim, :help diff
vimdiff
vim -d
は
$ vimdiff a.txt b.txt
とvimdiff
というコマンドを呼ぶのと同じです。
vimdiff
を確認してみるとただのvim
へのシンボリックリンクになってると
思いますが、
Vimではコマンド自体の名前をみて追加のオプションを渡す様になっています。
実際、
$ cd /tmp && touch a.txt b.txt
$ ln -s /usr/bin/vim ./vimdiff
$ ./vimdiff a.txt b.txt
とかすればdiffモードで立ち上がります。
:diffsplit
すでに立ち上げてる時に他のファイルと比較したいときは コマンドラインモードで
:diffsplit b.txt
とdiffsplit
(またはdiffs
)を使って他のファイルを開きます。
diffモードでの操作
[c
: 次のdiff箇所へ移動。]c
: 前のdiff箇所へ移動。:diffget
、:diffg
: diff行で現在のバッファの内容をもう片方のバッファへコピー。do
: “diff obtain”、diff行で現在のバッファの内容をもう片方のバッファへコピー。:diffput
、:diffpu
: diff行で現在のバッファの内容をもう片方のバッファへコピー。dp
: “diff put”、diff行で現在のバッファの内容をもう片方のバッファへコピー。diffoff
: diffモードを終了する。diffupdate
: diff状態をアップデート。
:diffget
とdo
、及び:diffput
とdp
は同じ操作ですが、
コマンドモードのdiffget
などは範囲を選んでVisualモードに入ってからも
使うことが出来、離れたdiffも一気にマージすることが可能です。
範囲を選んでからd
を押してしまうとその部分が消えてしまうので
do
、dp
はVisualモードでは使えません1。
3つ以上のファイルを同時に開いている時には、
:diffget 3
または
3do
の様にマージするバッファを指定します。
[c
、]c
とdo
、dp
をよく使います。
これらのコマンドでのマージは、diffのある行を含む範囲を選んでいるか、 diffのある行、またはその一つ下の行にいる時に出来ます。
相手にしか無い行はそもそも該当行にカーソルが行けませんが
一つ下の行に行くとdo
とかが使えます。
diffモードの設定
diffモードでは上に書いたように幾つかの設定が特別に自動でセットされたりしますが
diffモードの時だけ設定を変えたい時には
&diff
をチェックして行います。
1 2 3 4 5 6 7 |
|
こんな感じで。スペルチェックなんかは diffモードでもオンにしておくとかなり煩くなってしまうこともあるのでオフにしています。
wrapに関しては、違いの箇所を見るのに横にスクロールしないと見えないのは
結構面倒なのでwrapをオンにしています。
(wrap<
で<
を付けることでグローバルセッティングの値を使います。
普段はオンにしているので。
<
無しで常にオンにしてもOK。)
wrapをオンにすると、片方のファイルでwrapが必要ない程短い部分があると 左右の表示がズレてしまうことがあります。 そのような場合にはwrapをオフにした方が良いのですが、 通常比べるファイルでは同じような書式で同じような幅を持った物同士のものが多いので オンにして比べやすい方が便利な場合が多いです。
VimEnter
はVimを開くとき、FilterWritePre
は
diff
モードに入るときに該当するのでこれらの時に行うように。
また、diffモードの設定としてdiffopt
というパラメーターがあって、
これに以下の様な値を設定することが出来ます。
filter
: 片方だけに存在する行がある場合、無いファイルの方の行を空ける様になる。context:{n}
: 変更がある行間にn行表示する。それ以上ある場合にはfoldされる。設定が無いと6行。icase
: 大文字小文字を区別しない。iwhite
: スペースの違いは無視。horizontal
: 縦分割でdiffモード。vertical
: 縦分割でdiffモード。foldcolumn:{n}
: diffモード時のfoldcolumn(foldの状況を左側に表示、その幅)の設定。
現在の設定は以下のとおり。
1
|
|
また、diffモードで開いて片方を残してそのまま編集したい時、
diffモードが続いてしまって見難いのでdiffoff
をする必要がありますが、
これを自動で行う様に以下の様な設定をしておくと便利です。
1
|
|
diffの表示に使われるカラー設定は以下の4つで、
- DiffAdd: 比較相手に無い行。
- DiffDelte: 比較相手にあるが自分にない部分。
- DiffChange: 違いのある行。
- DiffText: 違いのある部分(必ずDiffChangeに該当する行の中になる)。
好みですが使ってるカラースキーマ(ron
)のものが余り気に入らなかったので
以下の様に設定しています。
1 2 3 4 |
|
:DiffOrig
Vimデフォルトコマンドではありませんが、 Helpに載ってるコマンドで、
1 2 3 4 5 |
|
の様なDiffOrig
というコマンドを作っておくと、
:DiffOrig
とすることで開いたファイルの初期状態からの違いをdiffモードで見ることが出来るようになります。
.vimrcに必須なものの一つ。
追記: 2016/03/08
splitright
をしておくと左側に編集中のファイル、右側に元のファイルを表示します。
(デフォルトではこのオプションはオフで、そのままだと右側に編集中のファイルがおかれる。)
追記ここまで
linediff.vim
linediff.vimは 任意の二箇所のdiffを表示してくれるプラグイン。
同一ファイル内の2箇所でも可能です。
まず、diffを見たい箇所の一つをVisualモードで選択し、
:LineDiff
コマンドを打ちます。するとその範囲の上と下側にマークがつくので、 その状態でもう一箇所へ移動してVisualモードに入って選択し、 再び
:LineDiff
すると先ほど選択した部分とのdiffが別枠で表示されます。
同じファイル内の同じ様な場所のdiffを見たり、 違うファイルでも一部だけ比較したい時などに便利です。
デフォルトの設定だと現在のバッファを後ろに回して 比較する者同士だけの表示に移ります。
作業中のバッファを表示したまま、新たにの方に違いを表示させるには
1 2 |
|
の様な設定をしておくと便利です。
これを知るまでは見たい部分だけ他のファイルに書きだして
vim -d
したりしてましたがこのプラグインで大分作業が楽になりました。
vcscommand.vim
vcscommand.vim はsvnやgit等のバージョン管理システム上のファイルを扱う際に 色々と便利にしてくれるプラグインです。
ファイルのコミットなども出来ますが、
この中にコマンド:VCSVimDiff
または<Leader>cv
で
現在開いているファイルの未コミット分の差分を見ることが出来ます。
基本ターミナルで作業するのでgitコマンドなどをこのプラグインで使うことはありませんが、 このdiff機能はとても便利でよく使います。 無いと困るくらい。
vcscommand.vimの他の機能については以下の記事が詳しいです。
diffchar.vim
rickhowe/diffchar.vim はdiffの表示時に単語単位のハイライトを強化してくれるプラグイン。
追記: 2016/03/08
元々、 vim-scripts/diffchar.vim というvim-scriptsレポジトリにあるものを使っていましたが、 今は作者の人が上の自分のレポジトリに最新版を公開しています。
最新版の方では下に書く様にオプションのデフォルトが変更されていたり ヘルプが入っていたりします。
追記ここまで
通常、diffモードでは行内に違う部分がある場合、
違う部分が初めて出たところから最後に出るところまで全体がDiffText
のハイライト対象になります。
aaa bbb ccc ddd eee fff ggg hhh
と
aaa bbb xxx ddd eee xxx ggg hhh
を比較した場合、ここではccc
とfff
の部分が違いますが、
ccc ddd eee fff
の部分がハイライトされます。
これがdiffchar.vimを入れるとccc
とfff
の部分だけがハイライトされる様になります。
ただ、場合によっては逆に見づらくなることもあるので 使ってみて、という感じです。
最初入れてちょっとあれかな、と思って外してましたが 今はまた入れています。
追記: 2016/03/08
この辺の見づらくなる所は vim-scripts/diffchar.vim でのデフォルトが一文字単位でチェックしてハイライトする所が原因です。
aaa
とaba
みたいのがある場合にb
の部分だけをハイライトするような。
これだけだと別に良いのですが、長い文章で全然違う単語が並んでいるのに、
逆に幾つかの文字はたまたま合うのでそれらを除いた部分がハイライトされる
様な事が起こります。
これはg:DiffUnit
というオプションで変更できます。
1
|
|
- ‘Word1’ : \w+ word and any \W single character (default)
- ‘Word2’ : non-space and space words
- ‘Word3’ : < or > character class boundaries
- ‘Char’ : any single character
- ‘CSV(,)’ : separated by characters such as ‘,’, ‘;’, and ‘\t’
以前のvim-scriptsにあるレポジトリのもの(v5.5)では ‘Char’がデフォルトでしたが、 rickhowe/diffchar.vim では’Word1’がデフォルトになっていて、 単語単位でハイライトされるので見やすくなります。
追記ここまで
vim-diff-enhanced
vim-diff-enhanced はdiffを作るアルゴリズムを変更できるプラグイン。
diffモードで、
:PatienceDiff
とすると、Patienceアルゴリズムと言うVimで使っているアルゴリズムとは 違うアルゴリズムでdiffを再描写します。
:EnhancedDiffDisable
で元に。
GitHubのREADMEにある例だと、 同じような内容の関数がいくつか続くような時、 本来比べてほしくない部分を比較してしまう時がありますが、 Patienceを使うと綺麗に分けてくれています。
これも場合によってはデフォルトの方が良い場合もありますが、 上記のコマンドで簡単に元に戻せるので入れておくと便利です。
READMEにあるように、デフォルトをPatienceにするように
1 2 3 |
|
の設定を.vimrcで行っています。
-
同じような理由で、
:diffget
に対してdg
を使えないのは、d
がdelete
のコマンドでもあるので、dgg
(現在いる行から上を全て削除)の一部だったりするため。 ↩