branch: externals/org
commit 06f58e47594e208d290973fd488bb2bf88bfa9d8
Author: Ihor Radchenko <[email protected]>
Commit: Ihor Radchenko <[email protected]>
org-element-cache-map: Fix when FUNC deletes current element
* lisp/org-element.el (org-element-cache-map-continue-from): New
variable forcing `org-element-cache-map' to continue from a custom
point in buffer.
(org-element-cache-map): Add support for
`org-element-cache-map-continue-from'. Update docstring accordingly.
Also, make sure that mapping terminates correctly when FUNC deletes
all elements in buffer.
* testing/lisp/test-org.el (test-org/map-entries): Add test.
Fixes
https://orgmode.org/list/CADywB5KOJ1p0NpvA=iX-ybHsO=huga8ql3xmputetms2qp7...@mail.gmail.com
---
lisp/org-element.el | 30 +++++++++++++++++++++++-------
lisp/org.el | 1 +
testing/lisp/test-org.el | 11 ++++++++++-
3 files changed, 34 insertions(+), 8 deletions(-)
diff --git a/lisp/org-element.el b/lisp/org-element.el
index be48bf5004..e0450924eb 100644
--- a/lisp/org-element.el
+++ b/lisp/org-element.el
@@ -7118,6 +7118,10 @@ buffers."
(defvar warning-minimum-log-level) ; Defined in warning.el
(defvar org-element-cache-map--recurse nil)
+(defvar org-element-cache-map-continue-from nil
+ "Position from where mapping should continue.
+This variable can be set by called function, especially when the
+function modified the buffer.")
;;;###autoload
(cl-defun org-element-cache-map (func &key (granularity 'headline+inlinetask)
restrict-elements
next-re fail-re from-pos (to-pos
(point-max-marker)) after-element limit-count
@@ -7127,8 +7131,14 @@ GRANULARITY. Collect non-nil return values into result
list.
FUNC should accept a single argument - the element.
-FUNC can safely modify the buffer, but doing so may reduce
-performance.
+FUNC can modify the buffer, but doing so may reduce performance. If
+buffer is modified, the mapping will continue from an element starting
+after the last mapped element. If the last mapped element is deleted,
+the subsequent element will be skipped as it cannot be distinguished
+deterministically from a changed element. If FUNC is expected to
+delete the element, it should directly set the value of
+`org-element-cache-map-continue-from' to force `org-element-cache-map'
+continue from the right point in buffer.
If some elements are not yet in cache, they will be added.
@@ -7264,7 +7274,7 @@ the cache."
(setq start (match-beginning 0))
(setq start (max (or start -1)
(or
(org-element-property :begin data) -1)
- (org-element-property
:begin (element-match-at-point)))))
+ (or
(org-element-property :begin (element-match-at-point)) -1))))
(when (>= start to-pos)
(cache-walk-abort)))
(cache-walk-abort))))
;; Find expected begin position of an element after
@@ -7507,6 +7517,7 @@ the cache."
;; DATA matches restriction. FUNC may
;;
;; Call FUNC. FUNC may move point.
+ (setq org-element-cache-map-continue-from nil)
(if org-element--cache-map-statistics
(progn
(setq before-time (float-time))
@@ -7523,6 +7534,8 @@ the cache."
(setq last-match (car result))
;; If FUNC moved point forward, update
;; START.
+ (when org-element-cache-map-continue-from
+ (goto-char
org-element-cache-map-continue-from))
(when (> (point) start)
(move-start-to-next-match nil))
;; Drop nil.
@@ -7541,7 +7554,6 @@ the cache."
(eq cache-size (cache-size)))
;; START may no longer be valid, update
;; it to beginning of real element.
- (when start (goto-char start))
;; Upon modification, START may lay
;; inside an element. We want to move
;; it to real beginning then despite
@@ -7553,11 +7565,15 @@ the cache."
;; Make sure that we continue from an
;; element past already processed
;; place.
- (when (<= start (org-element-property :begin
data))
+ (when (and (<= start (org-element-property
:begin data))
+ (not
org-element-cache-map-continue-from))
(goto-char start)
(setq data (element-match-at-point))
- (goto-char (next-element-start))
- (move-start-to-next-match next-element-re))
+ ;; If DATA is nil, buffer is
+ ;; empty. Abort.
+ (when data
+ (goto-char (next-element-start))
+ (move-start-to-next-match next-element-re)))
(org-element-at-point to-pos)
(cache-walk-restart))
;; Reached LIMIT-COUNT. Abort.
diff --git a/lisp/org.el b/lisp/org.el
index ce4e08eab1..e2f315a4c5 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -11641,6 +11641,7 @@ headlines matching this string."
(goto-char (1- (org-element-property :end el))))))
;; Get the correct position from where to continue
(when org-map-continue-from
+ (setq org-element-cache-map-continue-from
org-map-continue-from)
(goto-char org-map-continue-from))
;; Return nil.
nil)
diff --git a/testing/lisp/test-org.el b/testing/lisp/test-org.el
index 056ea7d87a..97a84f5716 100644
--- a/testing/lisp/test-org.el
+++ b/testing/lisp/test-org.el
@@ -2405,7 +2405,16 @@ SCHEDULED: <2014-03-04 tue.>"
(equal '(22)
(org-test-with-temp-text "* H1 :yes:\n* H2 :no:\n* H3 :yes:no:"
(let (org-odd-levels-only)
- (org-map-entries #'point "yes&no"))))))
+ (org-map-entries #'point "yes&no")))))
+ ;; Setting `org-map-continue-from'
+ (should
+ (string= ""
+ (org-test-with-temp-text "* H1\n* H2\n* H3n* H4"
+ (org-map-entries
+ (lambda ()
+ (org-cut-subtree)
+ (setq org-map-continue-from (point))))
+ (buffer-string)))))
(ert-deftest test-org/edit-headline ()
"Test `org-edit-headline' specifications."