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:
parent
c22697f472
commit
23f9347d1a
|
@ -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,61 +848,78 @@ 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
|
||||||
(no-recursion (if (listp no-recursion) no-recursion
|
(let* ((types (pcase types
|
||||||
(list no-recursion)))
|
((pred listp) types)
|
||||||
--acc)
|
(`t t)
|
||||||
(letrec ((--walk-tree
|
(_ (list types))))
|
||||||
(lambda (--data)
|
(no-recursion (if (listp no-recursion) no-recursion
|
||||||
;; Recursively walk DATA. INFO, if non-nil, is a plist
|
(list no-recursion)))
|
||||||
;; holding contextual information.
|
--acc)
|
||||||
(let ((--type (org-element-type --data))
|
(letrec ((--walk-tree
|
||||||
recurse)
|
(lambda (--data)
|
||||||
(cond
|
;; Recursively walk DATA. INFO, if non-nil, is a plist
|
||||||
((not --data))
|
;; holding contextual information.
|
||||||
;; Ignored node in an export context.
|
(let ((--type (org-element-type --data t))
|
||||||
((and ignore (memq --data ignore)))
|
recurse)
|
||||||
;; List of elements or objects.
|
|
||||||
((not --type) (mapc --walk-tree --data))
|
|
||||||
(t
|
|
||||||
;; Check if TYPE is matching among TYPES. If so,
|
|
||||||
;; apply FUN to --DATA and accumulate return value
|
|
||||||
;; into --ACC (or exit if FIRST-MATCH is non-nil).
|
|
||||||
(setq recurse t)
|
|
||||||
(when (memq --type types)
|
|
||||||
(let ((result
|
|
||||||
(catch :org-element-skip
|
|
||||||
(setq recurse nil)
|
|
||||||
(prog1 (funcall fun --data)
|
|
||||||
(setq recurse t)))))
|
|
||||||
(cond ((not result))
|
|
||||||
(first-match (throw :--map-first-match result))
|
|
||||||
(t (push result --acc)))))
|
|
||||||
;; Determine if a recursion into --DATA is possible.
|
|
||||||
(cond
|
(cond
|
||||||
;; No recursion requested.
|
((not --data))
|
||||||
((not recurse))
|
((not --type))
|
||||||
;; --TYPE is explicitly removed from recursion.
|
;; Ignored node in an export context.
|
||||||
((memq --type no-recursion))
|
((and ignore (memq --data ignore)))
|
||||||
;; In any other case, map secondary, affiliated, and contents.
|
;; List of elements or objects.
|
||||||
|
((eq --type 'anonymous)
|
||||||
|
(mapc --walk-tree (org-element-contents --data)))
|
||||||
(t
|
(t
|
||||||
(when with-properties
|
;; Check if TYPE is matching among TYPES. If so,
|
||||||
(dolist (p with-properties)
|
;; apply FUN to --DATA and accumulate return value
|
||||||
(funcall --walk-tree (org-element-property p --data))))
|
;; into --ACC (or exit if FIRST-MATCH is non-nil).
|
||||||
(unless no-secondary
|
(setq recurse t)
|
||||||
(dolist (p (org-element-property :secondary --data))
|
(when (or (eq types t) (memq --type types))
|
||||||
(funcall --walk-tree (org-element-property p --data))))
|
(let ((result
|
||||||
(mapc --walk-tree (org-element-contents --data))))))))))
|
(catch :org-element-skip
|
||||||
(catch :--map-first-match
|
(setq recurse nil)
|
||||||
(funcall --walk-tree data)
|
(prog1 (funcall fun --data)
|
||||||
;; Return value in a proper order.
|
(setq recurse t)))))
|
||||||
(nreverse --acc)))))
|
(cond ((not result))
|
||||||
|
(first-match (throw :--map-first-match result))
|
||||||
|
(t (push result --acc)))))
|
||||||
|
;; Determine if a recursion into --DATA is possible.
|
||||||
|
(cond
|
||||||
|
;; No recursion requested.
|
||||||
|
((not recurse))
|
||||||
|
;; --TYPE is explicitly removed from recursion.
|
||||||
|
((memq --type no-recursion))
|
||||||
|
;; In any other case, map secondary, affiliated, and contents.
|
||||||
|
(t
|
||||||
|
(when with-properties
|
||||||
|
(dolist (p with-properties)
|
||||||
|
(funcall
|
||||||
|
--walk-tree
|
||||||
|
(if no-undefer
|
||||||
|
(org-element-property-1 p --data)
|
||||||
|
(org-element-property p --data)))))
|
||||||
|
(unless no-secondary
|
||||||
|
(dolist (p (org-element-property :secondary --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))))))))))
|
||||||
|
(catch :--map-first-match
|
||||||
|
(funcall --walk-tree data)
|
||||||
|
;; Return value in a proper order.
|
||||||
|
(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.
|
||||||
|
|
|
@ -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,32 +4649,35 @@ 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?
|
||||||
(cl-intersection
|
(or (eq types t)
|
||||||
(cons 'plain-text org-element-all-objects) types))
|
(cl-intersection
|
||||||
(no-recursion
|
(cons 'plain-text org-element-all-objects)
|
||||||
(append
|
(if (listp types) types (list types)))))
|
||||||
(if (listp no-recursion) no-recursion
|
(no-recursion
|
||||||
(list no-recursion))
|
(append
|
||||||
(unless objects?
|
(if (listp no-recursion) no-recursion
|
||||||
org-element-all-objects)
|
(list no-recursion))
|
||||||
(unless objects?
|
(unless objects?
|
||||||
;; Do not recurse into elements that can only contain
|
org-element-all-objects)
|
||||||
;; objects.
|
(unless objects?
|
||||||
(cl-set-difference
|
;; Do not recurse into elements that can only contain
|
||||||
org-element-all-elements
|
;; objects.
|
||||||
org-element-greater-elements)))))
|
(cl-set-difference
|
||||||
(org-element-ast-map
|
org-element-all-elements
|
||||||
data types fun
|
org-element-greater-elements)))))
|
||||||
ignore-list first-match
|
(org-element-ast-map
|
||||||
no-recursion
|
data types fun
|
||||||
;; Affiliated keywords may only contain objects.
|
ignore-list first-match
|
||||||
(when (and with-affiliated objects?)
|
no-recursion
|
||||||
(mapcar #'cdr org-element--parsed-properties-alist))
|
;; Affiliated keywords may only contain objects.
|
||||||
;; Secondary strings may only contain objects.
|
(when (and with-affiliated objects?)
|
||||||
(not objects?))))
|
(mapcar #'cdr org-element--parsed-properties-alist))
|
||||||
|
;; Secondary strings may only contain objects.
|
||||||
|
(not objects?)
|
||||||
|
no-undefer))))
|
||||||
|
|
||||||
;; The following functions are internal parts of the parser.
|
;; The following functions are internal parts of the parser.
|
||||||
;;
|
;;
|
||||||
|
|
Loading…
Reference in New Issue