Hi again,
I solved this for myself overriding org-map-entries. Implementing it was
simpler than expected. Let's see if we can agree on how to get this into
the core.
See attached a patch with a proposal to open the discussion. Sorry if I
did a mess with indenting the function, which has tabs and spaces
altogether.
I needed to add a save-excursion-window function to avoid being in
another file [1] after executing the function org-map-entries. I put it
close to the save-excursion function. I hope that does not break
anything else in the function.
Next is just a fun-call method, and here we could go for two ways:
Option 1 (what is proposed in the patch). more user friendly but more
restricted
Do the org-link-open-from-string inside the function and prepare to
parse the subtree, easier to use, of course, limited to that. But
org-link is very extensible itself. [2]
Option 2. less user friendly but more freedom
Just do the funcall (then, less lines). In the docstring we could
add an example of how to use it (example where a long example is
provided with such freedom, see var calendar-intermonth-text)
This is, by the way, more similar to how works file+function (but
without the file argument) in org-capture [3]
I think Option 1 it is better for completeness and consistency.
With this, we got a powerful and extensible way to get to "any subtree
of any file", but just one file. For those who might need it: how to
extend something like this for multiple files? I would not like to do
this, but just to let you know future work or how to continue. We
evaluate the function and we expect a string, if we have a list instead,
then, this might be handled with a loop to get all the strings inside
the list.
This is by the way, an approach to speedup processing on certain
scenarios: when all data is in a subtree inside a file
Cheers,
pinmacs
[1] Because in my scenario I have a file named "queries" which contain
some propview blocks; the data-diary is in another one
[2]
https://orgmode.org/guide/Hyperlinks.html
https://orgmode.org/manual/Handling-Links.html
[3] https://orgmode.org/manual/Template-elements.html
From aff7c87d7782145131e05e28ed6021ca28754f1c Mon Sep 17 00:00:00 2001
From: pinmacs <pinm...@cas.cat>
Date: Wed, 20 Aug 2025 13:03:00 +0200
Subject: [PATCH] org-map-entries: add scope function
---
lisp/org/org.el | 115 +++++++++++++++++++++++++-----------------------
1 file changed, 61 insertions(+), 54 deletions(-)
diff --git a/lisp/org/org.el b/lisp/org/org.el
index 9051bf6c8c9..ba92d34d842 100644
--- a/lisp/org/org.el
+++ b/lisp/org/org.el
@@ -12615,60 +12615,67 @@ org-map-entries
(t (setq matcher (if match (cdr (org-make-tags-matcher match)) t))))
(save-excursion
- (save-restriction
- (cond ((eq scope 'tree)
- (org-back-to-heading t)
- (org-narrow-to-subtree)
- (setq scope nil))
- ((and (or (eq scope 'region) (eq scope 'region-start-level))
- (org-region-active-p))
- ;; If needed, set start-level to a string like "2"
- (when start-level
- (save-excursion
- (goto-char (region-beginning))
- (unless (org-at-heading-p) (outline-next-heading))
- (setq start-level (org-current-level))))
- (narrow-to-region (region-beginning)
- (save-excursion
- (goto-char (region-end))
- (unless (and (bolp) (org-at-heading-p))
- (outline-next-heading))
- (point)))
- (setq scope nil)))
-
- (if (not scope)
- (progn
- ;; Agenda expects a file buffer. Skip over refreshing
- ;; agenda cache for non-file buffers.
- (when buffer-file-name
- (org-agenda-prepare-buffers
- (and buffer-file-name (list (current-buffer)))))
- (setq res
- (org-scan-tags
- func matcher org--matcher-tags-todo-only start-level)))
- ;; Get the right scope
- (cond
- ((and scope (listp scope) (symbolp (car scope)))
- (setq scope (eval scope t)))
- ((eq scope 'agenda)
- (setq scope (org-agenda-files t)))
- ((eq scope 'agenda-with-archives)
- (setq scope (org-agenda-files t))
- (setq scope (org-add-archive-files scope)))
- ((eq scope 'file)
- (setq scope (and buffer-file-name (list buffer-file-name))))
- ((eq scope 'file-with-archives)
- (setq scope (org-add-archive-files (list (buffer-file-name))))))
- (org-agenda-prepare-buffers scope)
- (dolist (file scope)
- (with-current-buffer (org-find-base-buffer-visiting file)
- (org-with-wide-buffer
- (goto-char (point-min))
- (setq res
- (append
- res
- (org-scan-tags
- func matcher org--matcher-tags-todo-only)))))))))
+ (save-window-excursion
+ (save-restriction
+ (cond ((eq scope 'tree)
+ (org-back-to-heading t)
+ (org-narrow-to-subtree)
+ (setq scope nil))
+ ((functionp scope)
+ (let ((result (funcall scope)))
+ (org-link-open-from-string result))
+ (org-back-to-heading t)
+ (org-narrow-to-subtree)
+ (setq scope nil))
+ ((and (or (eq scope 'region) (eq scope 'region-start-level))
+ (org-region-active-p))
+ ;; If needed, set start-level to a string like "2"
+ (when start-level
+ (save-excursion
+ (goto-char (region-beginning))
+ (unless (org-at-heading-p) (outline-next-heading))
+ (setq start-level (org-current-level))))
+ (narrow-to-region (region-beginning)
+ (save-excursion
+ (goto-char (region-end))
+ (unless (and (bolp) (org-at-heading-p))
+ (outline-next-heading))
+ (point)))
+ (setq scope nil)))
+
+ (if (not scope)
+ (progn
+ ;; Agenda expects a file buffer. Skip over refreshing
+ ;; agenda cache for non-file buffers.
+ (when buffer-file-name
+ (org-agenda-prepare-buffers
+ (and buffer-file-name (list (current-buffer)))))
+ (setq res
+ (org-scan-tags
+ func matcher org--matcher-tags-todo-only start-level)))
+ ;; Get the right scope
+ (cond
+ ((and scope (listp scope) (symbolp (car scope)))
+ (setq scope (eval scope t)))
+ ((eq scope 'agenda)
+ (setq scope (org-agenda-files t)))
+ ((eq scope 'agenda-with-archives)
+ (setq scope (org-agenda-files t))
+ (setq scope (org-add-archive-files scope)))
+ ((eq scope 'file)
+ (setq scope (and buffer-file-name (list buffer-file-name))))
+ ((eq scope 'file-with-archives)
+ (setq scope (org-add-archive-files (list (buffer-file-name))))))
+ (org-agenda-prepare-buffers scope)
+ (dolist (file scope)
+ (with-current-buffer (org-find-base-buffer-visiting file)
+ (org-with-wide-buffer
+ (goto-char (point-min))
+ (setq res
+ (append
+ res
+ (org-scan-tags
+ func matcher org--matcher-tags-todo-only))))))))))
res)))
;;; Properties API
--
2.39.5