Thank you for bringing this up!  You have helped me discover a long standing
issue I've had with emacs!

`next-error' calls `next-error-find-buffer' to determine where to find the next
error.  In that function it actually prioritizes the last buffer it was used in
over the current buffer!  This explains a lot of confusing behaviour I've
experienced when switching back and forth between grep and compilation buffers!

Looking through the source code it seems the "solution" is to manually set
`next-error-last-buffer' as grep, compile, occur, and xref do.  While I'm not a
fan of this, I suppose we should do what everyone else does.

I made some patches to fix the problem.  See attached

While I was looking at it I also removed an incorrect sentence from the
docstring of `org-highlight-sparse-tree-matches'.  The highlights automatically
disapper on edit for org-occur matches but not for sparse trees

>From 82d1637f94bec3c1b5f1dfb123c19f9067bde6f0 Mon Sep 17 00:00:00 2001
From: Morgan Smith <[email protected]>
Date: Tue, 7 Oct 2025 14:42:12 -0400
Subject: [PATCH 1/2] test-org/sparse-tree-next-error: New test

* testing/lisp/test-org.el (test-org/sparse-tree-next-error): New
test.
---
 testing/lisp/test-org.el | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/testing/lisp/test-org.el b/testing/lisp/test-org.el
index 96b45fbb8..062962c01 100644
--- a/testing/lisp/test-org.el
+++ b/testing/lisp/test-org.el
@@ -8015,6 +8015,43 @@ test-org/match-sparse-tree
      (search-forward "H2")
      (org-invisible-p2))))
 
+(ert-deftest test-org/sparse-tree-next-error ()
+  "Test calling `next-error' on sparse trees."
+  (org-test-with-temp-text "* H :tag:\n** H1 :tag:\n** H2 :tag:\n"
+    (org-match-sparse-tree nil "tag")
+    (should
+     (string-equal
+      "* H :tag:"
+      (buffer-substring-no-properties (point) (pos-eol))))
+    (next-error)
+    (should
+     (string-equal
+      "** H1 :tag:"
+      (buffer-substring-no-properties (point) (pos-eol))))
+    (next-error)
+    (should
+     (string-equal
+      "** H2 :tag:"
+      (buffer-substring-no-properties (point) (pos-eol))))
+    ;; Now switch to another buffer and try again leaving the first one intact
+    (should-error ;; TODO: "No more matches"
+     (org-test-with-temp-text "* 2H :tag:\n** 2H1 :tag:\n** 2H2 :tag:\n"
+       (org-match-sparse-tree nil "tag")
+       (should
+        (string-equal
+         "* 2H :tag:"
+         (buffer-substring-no-properties (point) (pos-eol))))
+       (next-error)
+       (should
+        (string-equal
+         "** 2H1 :tag:"
+         (buffer-substring-no-properties (point) (pos-eol))))
+       (next-error)
+       (should
+        (string-equal
+         "** 2H2 :tag:"
+         (buffer-substring-no-properties (point) (pos-eol))))))))
+
 (ert-deftest test-org/occur ()
   "Test `org-occur' specifications."
   ;; Count number of matches.

base-commit: 4611c2b7a7162e5c340c10cfd79f3a28c84ea659
-- 
2.51.0

>From 05a915a5ebb1d13d4b99bff2581ec1d37b887ec1 Mon Sep 17 00:00:00 2001
From: Morgan Smith <[email protected]>
Date: Tue, 7 Oct 2025 19:13:11 -0400
Subject: [PATCH 2/2] Fix `next-error' behavior with sparse trees

* lisp/org.el (org-highlight-sparse-tree-matches): Adjust docstring.
(org-scan-tags): Set `next-error-last-buffer' when adding
highlighting.
* testing/lisp/test-org.el (test-org/sparse-tree-next-error): Show
fixed behavior.  Remove todo.
---
 lisp/org.el              |  6 +++---
 testing/lisp/test-org.el | 33 ++++++++++++++++-----------------
 2 files changed, 19 insertions(+), 20 deletions(-)

diff --git a/lisp/org.el b/lisp/org.el
index 95fd46b4a..dd2a20978 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -1782,8 +1782,7 @@ org-sparse-trees
 
 (defcustom org-highlight-sparse-tree-matches t
   "Non-nil means highlight all matches that define a sparse tree.
-The highlights will automatically disappear the next time the buffer is
-changed by an edit command."
+Must be non-nil to traverse the sparse tree using `next-error'."
   :group 'org-sparse-trees
   :type 'boolean)
 
@@ -11570,7 +11569,8 @@ org-scan-tags
 	       (and org-highlight-sparse-tree-matches
 		    (org-get-heading) (match-end 0)
 		    (org-highlight-new-match
-		     (match-beginning 1) (match-end 1)))
+		     (match-beginning 1) (match-end 1))
+                    (setq next-error-last-buffer (current-buffer)))
 	       (org-fold-show-context 'tags-tree))
 	      ((eq action 'agenda)
                (let* ((effort (org-entry-get (point) org-effort-property))
diff --git a/testing/lisp/test-org.el b/testing/lisp/test-org.el
index 062962c01..e7117d528 100644
--- a/testing/lisp/test-org.el
+++ b/testing/lisp/test-org.el
@@ -8034,23 +8034,22 @@ test-org/sparse-tree-next-error
       "** H2 :tag:"
       (buffer-substring-no-properties (point) (pos-eol))))
     ;; Now switch to another buffer and try again leaving the first one intact
-    (should-error ;; TODO: "No more matches"
-     (org-test-with-temp-text "* 2H :tag:\n** 2H1 :tag:\n** 2H2 :tag:\n"
-       (org-match-sparse-tree nil "tag")
-       (should
-        (string-equal
-         "* 2H :tag:"
-         (buffer-substring-no-properties (point) (pos-eol))))
-       (next-error)
-       (should
-        (string-equal
-         "** 2H1 :tag:"
-         (buffer-substring-no-properties (point) (pos-eol))))
-       (next-error)
-       (should
-        (string-equal
-         "** 2H2 :tag:"
-         (buffer-substring-no-properties (point) (pos-eol))))))))
+    (org-test-with-temp-text "* 2H :tag:\n** 2H1 :tag:\n** 2H2 :tag:\n"
+      (org-match-sparse-tree nil "tag")
+      (should
+       (string-equal
+        "* 2H :tag:"
+        (buffer-substring-no-properties (point) (pos-eol))))
+      (next-error)
+      (should
+       (string-equal
+        "** 2H1 :tag:"
+        (buffer-substring-no-properties (point) (pos-eol))))
+      (next-error)
+      (should
+       (string-equal
+        "** 2H2 :tag:"
+        (buffer-substring-no-properties (point) (pos-eol)))))))
 
 (ert-deftest test-org/occur ()
   "Test `org-occur' specifications."
-- 
2.51.0

Reply via email to