続・Mercurial の diff を美しく表示するために必要なたった 1つの設定
つい一昨日、Mercurial の diff を美しく表示するために必要なたった 1つの設定 という記事を書いたばかりですが、
diff-highlight の動作を見ているといくつか気になるところを見つけてしまいました。
diff-highlight のイケてないところ
差分の中で +/- の行数が一致していないと文字単位でのハイライトをしてくれない
こんな感じです。
編集前後の行数が一致するときだけハイライトしてくれるようです。
diff-highlight のコードを読むとこんなコメント付きで、行数が一致しない時は早々に諦めています。
# If we have mismatched numbers of lines on each side, we could try to # be clever and match up similar lines. But for now we are simple and # stupid, and only handle multi-line hunks that remove and add the same # number of lines. if (@$a != @$b) { print @$a, @$b; return; }
+/- の行が一致していても、行がずれてしまうと文字単位でのハイライトをしてくれない
行数が一致するときはちゃんとやってくれるよ!と思いつつ、実はそうではありません。
ハイライトの判定は + の 1行目と - の 1行目、+ の 2行目と - の 2行目…と順に比較していきます。
そのため、上の行を消して、下に一行追加して…のような編集をするとちゃんとハイライトしてくれなくなります。
この例だと、
- "-mq =" の行と "+pager = /path/to/pager.py" の行を比較
- "-pager =" の行と空行を比較
しているので、書き足したはずの /path/to/pager.py はハイライトされません。
一行で 2箇所書き換えた場合は、ハイライト幅がとても大きくなる
例えば、ある箇所に括弧を付け加えてみると、書き換えていない箇所までハイライトされます。
これは、diff-highlight の実装が行頭と行末の一致する部分(common prefix, common suffix)を除いて、
それ以外をハイライトしているのでこうなります。
この動きは割とダメージが大きくて、ダブルクオートをシングルクオートに書き換えるようなケースでは、
文字列全体がハイライトされることになります。
困ったら手を動かせ
というわけで、hg-diff-highlight という Mercurial 拡張を書きました。
まだできたてホヤホヤで README すら書いていない体たらくなのですが、
ひとまず上記の問題はクリアするようなものになっています。
ちなみに 2枚目の例が /path/to/pager.py ではなく /path になっていますが、
変更箇所が多すぎる場合は異なる行とみなしてしまうため、ハイライトされなくなります。
ちょっと恣意的な例の上げ方でごめんなさい orz
hg-diff-highlight の使い方
任意のパスに hg clone します。
$ hg clone https://bitbucket.org/tk0miya/hg-diff-highlight
訂正 12/20: バージョン 0.1.0 リリースによりインストール方法が変更になりました。
diff-highlight パッケージをインストールします。
$ pip install diff-highlight
hgrc の extensions に書き足します。
なお、ハイライト処理は color 拡張に依存しているので、color 拡張が有効になっている必要があります。
[extensions] color = diff-highlight =
あとは hg diff して楽しみましょう。
なお、mercurial では diff が出てくる箇所がたくさんありますが、hg-diff-highlight は全てに対応している(はず)です。
@tk0miya 現状では、pager 経由で常時 "diff-hilight.pl | less -Fr" を使用する、みたいに割り切るのが良いでしょうね。diff以外にも log -p、tip -p、export、record 使用時等でも差分表示がありますし……
— FUJIWARA Katsunori (@flyingfoozy) 2013, 12月 16
まとめ
- diff-highlight は思ったより簡易な作りになっていた
- 勢い余って hg-diff-highlight という拡張を作った
- 今では反省している
(おまけ) 色を変更する場合
hg-diff-highlight は diff.inserted と diff.deleted をみて色を切り替えています(inverse 属性を付けている)
なので、diff の色を変更したい場合は通常の color 拡張と同じように書きます。
[color] diff.inserted = blue diff.deleted = magenta
もしあなたがハイライトしている箇所だけ色を変えたいという奇特な人の場合は、
diff.inserted_highlight と diff.deleted_highlight の値を設定するとよいでしょう。
color extension の 256色対応ってだれか手を出してたりするんですか? #mercurialjp
— Takeshi KOMIYA (@tk0miya) 2013, 12月 18