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
