Subject: bug#73172: [PATCH] Move to start of current header in diff-{file,hunk}-prev

From: Spencer Baugh <[email-masked]>
Date: Fri, 20 Sep 2024 13:24:55 -0400

Eli Zaretskii <[email-masked]> writes:

>> Cc: Stefan Monnier <[email-masked]>, [email-masked]
>> Date: Thu, 19 Sep 2024 23:46:00 +0300
>> From: Dmitry Gutov <[email-masked]>
>> 
>> On 19/09/2024 21:41, Spencer Baugh wrote:
>> 
>> >> and patch#2 seems good on balance.
>> >>
>> >> It does introduce some backward incompatibility in rare cases where I
>> >> have probably internalized the current behavior already -- for example
>> >> in the vc-print-root-log output pressing 'p' while on the first line
>> >> somewhere between the initial '*' and the end of the date dings with
>> >> "No previous log message", and how will move to bol.
>> >>
>> >> But it might be more consistent anyway, given that the there is no
>> >> ding already if you start out inside the summary text.
>> > 
>> > Yes.  It's definitely a change in behavior.
>> > 
>> > But, if someone has internalized:
>> > 
>> >    diff-file-prev usually acts like "backward-sexp for files" (it moves
>> >    point to the start of the current file), except that if point is in
>> >    the header of the first file in the buffer then diff-file-prev does
>> >    nothing instead.
>> > 
>> > Then I think they'll be happy to be able to discard that knowledge
>> > in favor of:
>> > 
>> >    diff-file-prev always acts like "backward-sexp for files" (it moves
>> >    point to the start of the current file).
>> > 
>> > Especially because "does nothing in one weird corner case" is not useful
>> > or deliberate behavior (it's just a bug).
>> 
>> Yeah, probably.
>> 
>> It kind of indicated "no elements above" right away, which is a tad 
>> meaningful, but indeed I struggle to produce a scenario where that would 
>> make a big difference.
>
> Please be sure to document all behavior changes in NEWS, if you
> install such changes.

Updated patch to add to NEWS.

>From d1481a60734c2ce7228cd356e7e0280e7e66cd34 Mon Sep 17 00:00:00 2001
From: Spencer Baugh <[email-masked]>
Date: Tue, 10 Sep 2024 14:18:39 -0400
Subject: [PATCH] Move to start of current header in diff-{file,hunk}-prev

If point was after a file or hunk header, the diff-file-prev and
diff-hunk-prev commands would move to the start of that header.
But if point was *within* the header, they would not move, and
would report "No previous file" or "No previous hunk".  This
differs from the behavior of most other movement commands,
e.g. backward-sexp or backward-sentence.

This commit fixes diff-file-prev and diff-hunk-prev, as well as
other easy-mmode-define-navigation BASE-prev commands.  Now
these commands move to the start of the containing "thing" just
like other movement commands.

* lisp/emacs-lisp/easy-mmode.el (easy-mmode--prev): Move to
start of current match first. (bug#73172)
* etc/NEWS: Document the behavior change.
---
 etc/NEWS                      |  6 ++++++
 lisp/emacs-lisp/easy-mmode.el | 11 +++++++++++
 2 files changed, 17 insertions(+)

diff --git a/etc/NEWS b/etc/NEWS
index 8bd5c7c9515..637a0e63acb 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -304,6 +304,12 @@ according to diffs in the current buffer, but without applying the diffs
 to the original text.  If the selected range extends a hunk, the
 command attempts to look up and copy the text in-between the hunks.
 
+---
+*** diff-file-prev and diff-hunk-prev reliably move to start of header.
+Previously, diff-file-prev and diff-hunk-prev would move when they were
+in the first header in the file, but not at the start of the header.
+Now they will reliably move to the start of the relevant header.
+
 ** php-ts-mode
 
 ---
diff --git a/lisp/emacs-lisp/easy-mmode.el b/lisp/emacs-lisp/easy-mmode.el
index d3dcab899d6..7a94d832273 100644
--- a/lisp/emacs-lisp/easy-mmode.el
+++ b/lisp/emacs-lisp/easy-mmode.el
@@ -772,6 +772,17 @@ easy-mmode--prev
   (unless count (setq count 1))
   (if (< count 0) (easy-mmode--next re name (- count) endfun narrowfun)
     (let ((re-narrow (and narrowfun (prog1 (buffer-narrowed-p) (widen)))))
+      ;; If point is inside a match for RE, move to its beginning like
+      ;; `backward-sexp' and other movement commands.
+      (when (and (not (zerop count))
+                 (save-excursion
+                   ;; Make sure we're out of the current match if any.
+                   (goto-char (if (re-search-backward re nil t 1)
+                                  (match-end 0) (point-min)))
+                   (re-search-forward re nil t 1))
+                 (< (match-beginning 0) (point) (match-end 0)))
+        (goto-char (match-beginning 0))
+        (setq count (1- count)))
       (unless (re-search-backward re nil t count)
         (user-error "No previous %s" name))
       (when re-narrow (funcall narrowfun)))))
-- 
2.39.3