I am sorry I wasted your time. Please see attached.

1. I have reworded and reformatted the commit log

2. I have added TINYCHANGE

3. For the test, I have corrected the local function, and instead of using
point, I am extracting the first few characters of each headline.  It makes
it easier to create new tests. Thank you for the suggestion



On Tue, Aug 5, 2025 at 12:15 PM Ihor Radchenko <yanta...@posteo.net> wrote:

> dmg <d...@turingmachine.org> writes:
>
> > The current logic of org-map-region uses two searches.
> > ...
>
> Duplicate of
> https://orgmode.org/list/m2ikj2bmeu....@turingmachine.org
> Canceled.
>
> --
> Ihor Radchenko // yantar92,
> Org mode maintainer,
> Learn more about Org mode at <https://orgmode.org/>.
> Support Org development at <https://liberapay.com/org-mode>,
> or support my work at <https://liberapay.com/yantar92>
>


-- 
--dmg

---
D M German
http://turingmachine.org
From 78d2924803567b6d6111a35ffdcf9dcef840b14a Mon Sep 17 00:00:00 2001
From: Daniel M German <dmg@turingmachine.org>
Date: Mon, 4 Aug 2025 18:03:13 -0700
Subject: [PATCH] org.el: make `org-map-region' properly set point at first
 heading

* lisp/org.el (org-map-region): Add a call to `goto-char' to go
to the beginning of the match after the first search.

* testing/lisp/test-org.el (test-org/map-region): Add tests
for `org-map-region'.

The current logic of `org-map-region' uses two searches.

In the first, the point is left after the asterisks of the heading.
In the subsequent calls, the point is correctly set to the first
asterisk of the headline.

This change makes sure the first header is processed the same way
as the rest.

TINYCHANGE
---
 lisp/org.el              |  5 ++-
 testing/lisp/test-org.el | 71 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 75 insertions(+), 1 deletion(-)

diff --git a/lisp/org.el b/lisp/org.el
index 65abfbe1a..626e44585 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -7078,13 +7078,16 @@ After top level, it switches back to sibling level."
 	(funcall fun)))))
 
 (defun org-map-region (fun beg end)
-  "Call FUN for every heading between BEG and END."
+  "Call FUN for every heading between BEG and END.
+The point is placed at the beginning of each heading
+(including any *) before FUN is called."
   (let ((org-ignore-region t))
     (save-excursion
       (setq end (copy-marker end))
       (goto-char beg)
       (when (and (re-search-forward org-outline-regexp-bol nil t)
 		 (< (point) end))
+        (goto-char (match-beginning 0))
 	(funcall fun))
       (while (and (progn
 		    (outline-next-heading)
diff --git a/testing/lisp/test-org.el b/testing/lisp/test-org.el
index 36dea35b7..345a5d06b 100644
--- a/testing/lisp/test-org.el
+++ b/testing/lisp/test-org.el
@@ -3161,6 +3161,77 @@ Let’s stop here
       (should (equal '("two")
                      (org-element-cache-map (lambda (el) (org-element-property :title el)) :next-re "TODO"))))))
 
+(ert-deftest test-org/map-region ()
+  "Test `org-map-region'."
+
+  (cl-flet
+      ;; return the first 5 characters of the current buffer
+      ((extract-first-5-chars ()
+         (buffer-substring (point) (min (+ (point) 5) (point-max))))
+       ;; org-map-region does not return anything so we need to
+       ;; wrap it in a function that saves the return value
+       ;; of the function applied to each header, and returns
+       ;; the results of applying such function as a list
+       (org-map-region-with-results  (fn)
+         (let (results)
+           (org-map-region
+            (lambda ()
+              (let ((result (funcall fn)))
+                (push result results)))
+            (point-min) (point-max))
+           (nreverse results))))
+    ;; each test returns the first 5 characters of each heading, including *
+    (dolist (org-element-use-cache '(t nil))
+      (should
+       (equal (list "* Lev" "** Le")
+	      (org-test-with-temp-text "* Level 1\n** Level 2"
+	                               (org-map-region-with-results #'extract-first-5-chars))))
+      (should
+       (equal (list "* Lev" "** Le")
+	      (org-test-with-temp-text "\n\n* Level 1\nSome text\n** Level 2"
+	                               (org-map-region-with-results #'extract-first-5-chars))))
+      (should
+       (equal (list "* Lev" "** Le" "* Lev" "** Le")
+	      (org-test-with-temp-text "
+:PROPERTIES:
+:ID:       some-id
+:END:
+* Level 1
+
+Some text
+
+** Level 2
+
+More text
+
+* Level 1 again
+
+** Level 2 again
+
+"
+	                               (org-map-region-with-results #'extract-first-5-chars))))
+      (should
+       (equal (list "* H1 " "* H2 " "* H3 " "* H4 " "* H5 ")
+              (org-test-with-temp-text "
+* H1 :BAR:
+:PROPERTIES:
+:TEST-FOO: 1
+:END:
+* H2 :FOO:
+:PROPERTIES:
+:TEST-FOO: 2
+:END:
+* H3 :BAR:
+:PROPERTIES:
+:-FOO: 1
+:END:
+* H4 :FOO:
+:PROPERTIES:
+:-FOO: 2
+:END:
+* H5 :TEST:"
+                                       (org-map-region-with-results #'extract-first-5-chars)))))))
+
 (ert-deftest test-org/edit-headline ()
   "Test `org-edit-headline' specifications."
   (should
-- 
2.43.0

Reply via email to