Emacs上でカラフルにdiffを表示する - 2012-04-03 - ククログ

ククログ

株式会社クリアコード > ククログ > Emacs上でカラフルにdiffを表示する

Emacs上でカラフルにdiffを表示する

ソフトウェア開発は小さな変更の積み重ねです。ソフトウェア開発ではバージョン管理システムを使うことが当たり前ですが、バージョン管理システムはその変更の積み重ねを記録しています。変更はdiffと呼ばれ、ソフトウェア開発をしていれば頻繁に目にします。例えば、コミット前に変更を最終確認するためにdiffを見ます。また、誰かがコミットすればdiff入りのメールで変更内容が関係者に通知されます。

さて、そんなよく目にするdiffをEmacs上でより見やすく表示する方法を紹介します。

そもそも、どうしてEmacs上でdiffを見るかというと、Emacsにはdiffを表示するための支援機能がたくさんあるからです。編集中のファイルのdiffを見たいならVCが提供するvc-diffC-x v =)を使います。バージョン管理システムで管理している複数のファイルのdiffを見たいならMagit(git用)やpsvn(Subversion用)などそれぞれのバージョン管理システムと連携する拡張パッケージの機能を使います。これらの機能を使うとコードを書きながらすぐに変更点を確認できるため、開発のリズムを崩さずにすみます。

行をカラフルにする

diffが簡単に見られる便利なEmacsですが、初期状態のdiff表示はあまり見やすくありません。

デフォルトのdiff表示

一番左に「-」がある行が削除された行で「+」がある行が追加された行ですが、パッと見てわかりません。

ということで、色をつけてみましょう。

;; 追加された行は緑で表示
(set-face-attribute 'diff-added nil
                    :foreground "white" :background "dark green")
;; 削除された行は赤で表示
(set-face-attribute 'diff-removed nil
                    :foreground "white" :background "dark red")

追加された行は緑っぽく、削除された行は赤っぽく表示します。

カラフルなdiff表示

色がついたのでパッと見て注目する場所がわかりますね。

ここでは、文字の色と背景色を両方指定しているので、フレームの色を白っぽくしていても黒っぽくしていてもどちらでも見やすく表示されます。自分でフェイスを変更して色を変える場合は、このように文字の色と背景色を両方指定するか、((class color) (background dark))などを使って白っぽいときと黒っぽいとき両方の設定をすることをオススメします。なお、文字の色と背景色を指定する方が楽です。

文字をカラフルにする

行に色を付けることでどの行が変更されたかをパッと見つけることができるようになりました。しかし、行の中のどの部分かはまだパッと見つけることはできません。行の中のどの部分が変更されたかを見つける方法はいくつかあります。例えば、gitには--word-diffというオプションがありますし、DocDiffというツールもあります。test-unit 2がやっている方法もあります。Cutterもtest-unit 2と同じ方法を使っています。

実はEmacsにも同じような機能があるのですが、あまり知られていないようです。おそらく、デフォルトのフェイスの設定が地味だからでしょう。以下のように設定してみてください。

;; 文字単位での変更箇所は色を反転して強調
(set-face-attribute 'diff-refine-change nil
                    :foreground nil :background nil
                    :weight 'bold :inverse-video t))

;; diffを表示したらすぐに文字単位での強調表示も行う
(defun diff-mode-refine-automatically ()
  (diff-auto-refine-mode t))
(add-hook 'diff-mode-hook 'diff-mode-refine-automatically)

文字単位の変更箇所は色を反転するようにして強調しています。

文字単位までカラフルなdiff表示

ぐっとわかりやすくなりました。nil"white"に変更していますね。

これらの機能はEmacsに標準でついているdiff-modeの機能です。

Magitのdiffもカラフルにする

Magitもdiff-modeを使っているのでこれまでの設定でdiffをカラフルに見やすくすることができます。しかし、ちょっとうまくないところがあるので、もうひと手間かけてみましょう。やることはここで設定したdiff-modeの表示をMagitでもできるようにすることだけです。

;; diffを表示しているときに文字単位での変更箇所も強調表示する
;; 'allではなくtにすると現在選択中のhunkのみ強調表示する
(setq magit-diff-refine-hunk 'all)
;; diffの表示設定が上書きされてしまうのでハイライトを無効にする
(set-face-attribute 'magit-item-highlight nil :inherit nil)

この設定がないと文字単位の違いを強調するためにひと手間増えたり、せっかくのカラフルな表示が見えなくなったりしまいます。この設定さえしておけば、Magitでもdiffを文字単位まで見やすく表示できます。

なお、psvnはこのような追加の設定をしなくてもdiff-mode用の設定が反映されます。

まとめ

Emacsでdiffをカラフルに見やすく表示する設定を紹介しました。まとめると以下のようになります。

;; diffの表示方法を変更
(defun diff-mode-setup-faces ()
  ;; 追加された行は緑で表示
  (set-face-attribute 'diff-added nil
                      :foreground "white" :background "dark green")
  ;; 削除された行は赤で表示
  (set-face-attribute 'diff-removed nil
                      :foreground "white" :background "dark red")
  ;; 文字単位での変更箇所は色を反転して強調
  (set-face-attribute 'diff-refine-change nil
                      :foreground nil :background nil
                      :weight 'bold :inverse-video t))
(add-hook 'diff-mode-hook 'diff-mode-setup-faces)

;; diffを表示したらすぐに文字単位での強調表示も行う
(defun diff-mode-refine-automatically ()
  (diff-auto-refine-mode t))
(add-hook 'diff-mode-hook 'diff-mode-refine-automatically)

;; diff関連の設定
(defun magit-setup-diff ()
  ;; diffを表示しているときに文字単位での変更箇所も強調表示する
  ;; 'allではなくtにすると現在選択中のhunkのみ強調表示する
  (setq magit-diff-refine-hunk 'all)
  ;; diff用のfaceを設定する
  (diff-mode-setup-faces)
  ;; diffの表示設定が上書きされてしまうのでハイライトを無効にする
  (set-face-attribute 'magit-item-highlight nil :inherit nil))
(add-hook 'magit-mode-hook 'magit-setup-diff)

その他のEmacsのオススメ設定が気になる人やEmacsを使いたくなったけどよい入門書はないかしら、という人はEmacs実践入門 - おすすめEmacs設定2012をどうぞ。

diffが見やすくなるとソースコードの変更を確認しやくなりますね。これまで以上に他の人のコミットも確認して、よくないコードを見つけたらどんどんよいコードにしていってください。