org-element-map: Allow TYPES t and add new arg NO-UNDEFER

* lisp/org-element-ast.el (org-element-ast-map):
* lisp/org-element.el (org-element-map): Treat TYPES t as all possible
types.  Add new optional parameter to no resolve deferred while
traversing the AST.
This commit is contained in:
Ihor Radchenko 2023-04-28 11:55:43 +02:00
parent c22697f472
commit 23f9347d1a
No known key found for this signature in database
GPG Key ID: 6470762A7DA11D8B
2 changed files with 108 additions and 75 deletions

View File

@ -817,13 +817,18 @@ The function takes care of setting `:parent' property for NEW."
old) old)
(defun org-element-ast-map (defun org-element-ast-map
(data types fun &optional ignore first-match no-recursion with-properties no-secondary) ( data types fun
&optional
ignore first-match no-recursion
with-properties no-secondary no-undefer)
"Map a function on selected syntax nodes. "Map a function on selected syntax nodes.
DATA is a syntax tree. TYPES is a symbol or list of symbols of DATA is a syntax tree. TYPES is a symbol or list of symbols of
node types. FUN is the function called on the matching nodes. node types. FUN is the function called on the matching nodes.
It has to accept one argument: the node itself. It has to accept one argument: the node itself.
When TYPES is t, call FUN for all the node types.
When optional argument IGNORE is non-nil, it should be a list holding When optional argument IGNORE is non-nil, it should be a list holding
nodes to be skipped. In that case, the listed nodes and their nodes to be skipped. In that case, the listed nodes and their
contents will be skipped. contents will be skipped.
@ -843,13 +848,20 @@ secondary properties.
When optional argument NO-SECONDARY is non-nil, do not recurse into When optional argument NO-SECONDARY is non-nil, do not recurse into
secondary strings. secondary strings.
When optional argument NO-UNDEFER is non-nil, do not resolve deferred
values.
FUN may also throw `:org-element-skip' signal. Then, FUN may also throw `:org-element-skip' signal. Then,
`org-element-ast-map' will not recurse into the current node. `org-element-ast-map' will not recurse into the current node.
Nil values returned from FUN do not appear in the results." Nil values returned from FUN do not appear in the results."
(declare (indent 2)) (declare (indent 2))
;; Ensure TYPES and NO-RECURSION are a list, even of one node. ;; Ensure TYPES and NO-RECURSION are a list, even of one node.
(let* ((types (if (listp types) types (list types))) (when types
(let* ((types (pcase types
((pred listp) types)
(`t t)
(_ (list types))))
(no-recursion (if (listp no-recursion) no-recursion (no-recursion (if (listp no-recursion) no-recursion
(list no-recursion))) (list no-recursion)))
--acc) --acc)
@ -857,20 +869,22 @@ Nil values returned from FUN do not appear in the results."
(lambda (--data) (lambda (--data)
;; Recursively walk DATA. INFO, if non-nil, is a plist ;; Recursively walk DATA. INFO, if non-nil, is a plist
;; holding contextual information. ;; holding contextual information.
(let ((--type (org-element-type --data)) (let ((--type (org-element-type --data t))
recurse) recurse)
(cond (cond
((not --data)) ((not --data))
((not --type))
;; Ignored node in an export context. ;; Ignored node in an export context.
((and ignore (memq --data ignore))) ((and ignore (memq --data ignore)))
;; List of elements or objects. ;; List of elements or objects.
((not --type) (mapc --walk-tree --data)) ((eq --type 'anonymous)
(mapc --walk-tree (org-element-contents --data)))
(t (t
;; Check if TYPE is matching among TYPES. If so, ;; Check if TYPE is matching among TYPES. If so,
;; apply FUN to --DATA and accumulate return value ;; apply FUN to --DATA and accumulate return value
;; into --ACC (or exit if FIRST-MATCH is non-nil). ;; into --ACC (or exit if FIRST-MATCH is non-nil).
(setq recurse t) (setq recurse t)
(when (memq --type types) (when (or (eq types t) (memq --type types))
(let ((result (let ((result
(catch :org-element-skip (catch :org-element-skip
(setq recurse nil) (setq recurse nil)
@ -889,15 +903,23 @@ Nil values returned from FUN do not appear in the results."
(t (t
(when with-properties (when with-properties
(dolist (p with-properties) (dolist (p with-properties)
(funcall --walk-tree (org-element-property p --data)))) (funcall
--walk-tree
(if no-undefer
(org-element-property-1 p --data)
(org-element-property p --data)))))
(unless no-secondary (unless no-secondary
(dolist (p (org-element-property :secondary --data)) (dolist (p (org-element-property :secondary --data))
(funcall --walk-tree (org-element-property p --data)))) (funcall
--walk-tree
(if no-undefer
(org-element-property-1 p --data)
(org-element-property p --data)))))
(mapc --walk-tree (org-element-contents --data)))))))))) (mapc --walk-tree (org-element-contents --data))))))))))
(catch :--map-first-match (catch :--map-first-match
(funcall --walk-tree data) (funcall --walk-tree data)
;; Return value in a proper order. ;; Return value in a proper order.
(nreverse --acc))))) (nreverse --acc))))))
(defun org-element-create (type &optional props &rest children) (defun org-element-create (type &optional props &rest children)
"Create a new syntax node of TYPE. "Create a new syntax node of TYPE.

View File

@ -4568,7 +4568,10 @@ If STRING is the empty string or nil, return nil."
rtn))))) rtn)))))
(defun org-element-map (defun org-element-map
(data types fun &optional info first-match no-recursion with-affiliated) ( data types fun
&optional
info first-match no-recursion
with-affiliated no-undefer)
"Map a function on selected elements or objects. "Map a function on selected elements or objects.
DATA is a parse tree (for example, returned by DATA is a parse tree (for example, returned by
@ -4579,6 +4582,8 @@ elements or object types (see `org-element-all-elements' and
function called on the matching element or object. It has to accept function called on the matching element or object. It has to accept
one argument: the element or object itself. one argument: the element or object itself.
When TYPES is t, call FUN for all the elements and objects.
When optional argument INFO is non-nil, it should be a plist When optional argument INFO is non-nil, it should be a plist
holding export options. In that case, elements of the parse tree holding export options. In that case, elements of the parse tree
\\(compared with `eq') not exportable according to `:ignore-list' \\(compared with `eq') not exportable according to `:ignore-list'
@ -4596,6 +4601,9 @@ When optional argument WITH-AFFILIATED is non-nil, FUN will also
apply to matching objects within parsed affiliated keywords (see apply to matching objects within parsed affiliated keywords (see
`org-element-parsed-keywords'). `org-element-parsed-keywords').
When optional argument NO-UNDEFER is non-nil, do not resolve deferred
values.
FUN may throw `:org-element-skip' signal. Then, `org-element-map' FUN may throw `:org-element-skip' signal. Then, `org-element-map'
will not recurse into the current element. will not recurse into the current element.
@ -4641,11 +4649,13 @@ looking into captions:
nil nil nil t)" nil nil nil t)"
(declare (indent 2)) (declare (indent 2))
;; Ensure TYPES and NO-RECURSION are a list, even of one element. ;; Ensure TYPES and NO-RECURSION are a list, even of one element.
(let* ((types (if (listp types) types (list types))) (when (and types data)
(ignore-list (plist-get info :ignore-list)) (let* ((ignore-list (plist-get info :ignore-list))
(objects? (objects?
(or (eq types t)
(cl-intersection (cl-intersection
(cons 'plain-text org-element-all-objects) types)) (cons 'plain-text org-element-all-objects)
(if (listp types) types (list types)))))
(no-recursion (no-recursion
(append (append
(if (listp no-recursion) no-recursion (if (listp no-recursion) no-recursion
@ -4666,7 +4676,8 @@ looking into captions:
(when (and with-affiliated objects?) (when (and with-affiliated objects?)
(mapcar #'cdr org-element--parsed-properties-alist)) (mapcar #'cdr org-element--parsed-properties-alist))
;; Secondary strings may only contain objects. ;; Secondary strings may only contain objects.
(not objects?)))) (not objects?)
no-undefer))))
;; The following functions are internal parts of the parser. ;; The following functions are internal parts of the parser.
;; ;;