Subject: bug#12747: 23.4; diff-auto-refine-mode process only last hunk in diff (must ALL).

From: Oleksandr Gavenko <[email-masked]>
Date: Sun, 28 Oct 2012 21:38:07 +0200

On 2012-10-28, Stefan Monnier wrote:

>> If I enable diff-auto-refine-mode in all diff-mode buffers:
>>   (defun my-diff-auto-refine-mode-on () (diff-auto-refine-mode 1))
>>   (add-hook 'diff-mode-hook 'my-diff-auto-refine-mode-on)
>> I see actions only on last hunk in diff.
>
> I'm not sure I understand what you mean.  `diff-auto-refine-mode' does
> not refine-highlight all the hunks at once (quoting the docstring):
>
>    When enabled, Emacs automatically highlights
>    changes in detail as the user visits hunks.
>
> "as the user visits the hunks" means that it's only highlighted in
> response to "n" and "p" (and a few related operations).
>
Ok. But it's difficult to understand. For example manual section
"22.10 Diff Mode" doesn't say anything about concepts of visiting hunks...

I forget add another essential details. I use this functionality with 'C-x v
=' (runs the command vc-diff). And got highlighting in detail only for last
hunk.

Next I save *vc-diff* buffer to file and reopen it. Now I got highlighting in
detail only in first hunk.

This behaviour frustrate me, until I got understanding of working model from
you.

> This is not a bug.  IIUC you'd like the refinement to be done in any
> hunk that is ever displayed, right?

Yes.

I never use "n" or "p" for moving around *diff* buffer. Just "arrows" and
"pages". So in my work-flow 'diff-auto-refine-mode' do nothing...

> If so, that is a valid request for enhancement, and I fully agree.

That is!

Also I would be glad to see alias for:

  (diff-auto-refine-mode 1)

in form:

  (defun diff-auto-refine-mode-on () (diff-auto-refine-mode 1))

to simplify usage in hooks...

> If someone is interested in implementing it, here's how I think it would
> have to work:
> - add a font-lock-keywords rule in diff-mode which simply registers the
>   region displayed in a buffer-local var `diff--regions-displayed'.
> - have an idle timer that checks `diff--regions-displayed' and refines
>   all the hunks in those regions (and it should also font-lock those
>   hunks at the same time, so that if some of the hunk is not yet
>   displayed and not yet font-locked, displaying it later on won't cause
>   re-refining the hunk).
>
Sound very good.

FYI I heard about refining in emacs-help:

  http://thread.gmane.org/gmane.emacs.help/87082/focus=87093
                Diff could also show the changes within lines

Tom suggest add to 'diff-mode-hook' such code:

  (save-excursion
    (goto-char (point-min))
    (while (not (eobp))
      (diff-hunk-next))))

As exercise I try make some code myself:

  (defvar diff-auto+-refine-idle-time 2
    "Time before highlighting take place XXX")

  (defvar diff-auto+-refine-idle-timer nil
    "Timer for highlighting XXX")

  (defun diff-auto+-refine-action ()
    "TODO how about preventing to process already processed
  regions??"
    (when (eq major-mode 'diff-mode)
      (message "%s: diff-auto+-refine-action" (format-time-string "%M:%S" (current-time)))
      (diff-refine-hunk)))

  (defun diff-auto+-refine-mode (&optional arg)
    "Auto refine current hunk in diff mode."
    (interactive "P")
    (if (not arg)
        (if diff-auto+-refine-idle-timer
            (diff-auto+-refine-mode -1)
          (diff-auto+-refine-mode 1))
      (if (and (number-or-marker-p arg) (< 0 (prefix-numeric-value arg)))
          (unless diff-auto+-refine-idle-timer
            (setq diff-auto+-refine-idle-timer
                  (run-with-idle-timer 2 t 'diff-auto+-refine-action)))
        (when diff-auto+-refine-idle-timer
          (cancel-timer diff-auto+-refine-idle-timer)
          (setq diff-auto+-refine-idle-timer nil)))))

which does not use 'font-lock-keywords'. I am inexperience Elisp hacker and
don't understand how can >>font-lock-keywords rule registers the region
displayed<<. Does this mean register MATCHER with always fail but perform side
effect by updating suggested 'diff--regions-displayed' variable?

Also I can't found function that return visible to user region to proper
highlight all visible hunks instead current...

As I have many question which involve teaching of me I ask them in
emacs-help:

  http://permalink.gmane.org/gmane.emacs.help/87474
                Function that return visible to user region and performing
                action on demand.
  http://permalink.gmane.org/gmane.emacs.help/87472
                idle-timer for processing all buffers with selected
                minor-mode.

-- 
Best regards!