ラベル diff-mode の投稿を表示しています。 すべての投稿を表示
ラベル diff-mode の投稿を表示しています。 すべての投稿を表示

2017年1月5日木曜日

Emacsのdiff-modeでauto-refinesの仕様変更とworkaround

diff-modeの移動に関する変更があった後、間も無く別のcommit (e5ef59b87da5c2ddfa22f7342efe29b3eea6ed97)でauto-refinesに関する仕様も変更されていた。

移動が確実に行われた時のみ、細かい変更点 (refines)をcoloringする挙動になった。これに伴いauto-refinesの関連codeが別の場所に移され、以前取った方法では移動するだけではrefinesへのcoloringが適用されなくなった。

対策として、「Emacsのdiff-modeでdiff-hunk-prev/next等の挙動が変更された」で紹介したcodeをベースにして以下のように変更し解決した:

(with-eval-after-load "diff-mode"
  (defun my-diff-hunk-next (&optional count)
    (interactive)
    (diff-hunk-next count nil)
    (diff-refine-hunk))
  (defun my-diff-hunk-prev (&optional count)
    (interactive)
    (diff-hunk-prev count nil)
    (diff-refine-hunk))
  ;; key bindings
  (define-key diff-mode-shared-map "n" 'my-diff-hunk-next)
  (define-key diff-mode-shared-map "p" 'my-diff-hunk-prev))

やっていることは、それぞれのfunction内で移動するためのfunctionを呼び出した後に、coloringする為のdiff-refine-hunkを呼び出すだけである。

2016年12月12日月曜日

Emacsのdiff-modeでdiff-hunk-prev/next等の挙動が変更された

diff-hunk-prevやdiff-hunk-nextといった、変更箇所間を移動するfunctionsにおいて、「header直下にあるhunkをskipする」よう挙動が変更された (@ commit 2c8a7e50d24daf19ea7d86f1cfeaa98a41c56085)。

例:

diff-modeで次のような表示があったとする (※1〜※3は場所の明示のためのマーク)

※1 diff --git a/path/to/changed/file b/path/to/changed/file
--- a/path/to/changed/file
+++ b/path/to/changed/file
※2 @@ -343,5 +343,10 @@
...HUNK 1...
※3 @@ -451,1 +451,3 @@
...HUNK 2...


最初のcursor positionが※1の時、従来はdiff-hunk-next ("n")で※2 → ※3と移動していた。しかし、今回の変更により※2は最初のhunkなのでskipされ、いきなり※3に飛んでしまう。

diff-hunk-prevも同じで、header直下のhunkはskipされるのがdefaultの挙動となっている。

何が問題か?


diff-modeで、具体的にどこが変更されたのかをわかりやすくする為に、diff-auto-refine-modeを設定している。これは、wdiffのように文字単位での変更を色付けしてくれるのだが、処理速度の問題からdiff-hunk-prevやdiff-hunk-nextでそのhunkをvisitした際に色付けされる仕組みである。

従って、今回の挙動変更によりheader直下の@@部分へのjumpがskipされると、diff-refine-hunkが適用されずに困る。

解決法

diff-hunk-next, diff-hunk-prevなどのoptional argumentsの一つであるskip-hunk-startにnilを渡して呼び出せば従来の挙動に戻る。

1. lambdaを使う

(with-eval-after-load "diff-mode"
  ;; diff-hunk-next
  (define-key diff-mode-shared-map "n"
    (lambda (&optional count)
      (interactive)
      (diff-hunk-next count nil)))
  ;; diff-hunk-prev
  (define-key diff-mode-shared-map "p"
    (lambda (&optional count)
      (interactive)
      (diff-hunk-prev count nil))))

2. オレオレfunctionを定義しkeybindする

(with-eval-after-load "diff-mode"
  (defun my-diff-hunk-next (&optional count)
    (interactive)
    (diff-hunk-next count nil))
  (defun my-diff-hunk-prev (&optional count)
    (interactive)
    (diff-hunk-prev count nil))
  ;; key bindings
  (define-key diff-mode-shared-map "n" 'my-diff-hunk-next)
  (define-key diff-mode-shared-map "p" 'my-diff-hunk-prev))

3. 気に入らない挙動を修正する

  • adviceを使う?
  • noflet, dfletあたりを使う?