(defvar orgia-transform-functions nil) (defun orgia-default-pre-filter (node) "Returns (node . children)" (if (listp node) (cons node node) (cons node nil))) (defun orgia-transform-tree-deep (tree &optional pre-filter post-filter) "Deep-first walk." ;; Queue items: ((node-cell . children) . next-list) (let* ((pre-filter (or pre-filter #'orgia-default-pre-filter)) (top (list tree)) (queue (list (cons (cons top top) top)))) (while queue (let* ((item (pop queue)) (next-list (cdr item))) (if (not next-list) ;; post; skip POST-FILTER for the list wrapping TREE (when (and queue post-filter) (let* ((node-cell-children (car item)) (children (cdr node-cell-children))) (setcar (car node-cell-children) (funcall post-filter (caar node-cell-children) children)))) ;; pre (setcdr item (cdr next-list)) (push item queue) (let* ((node-children (funcall pre-filter (car next-list))) (node (car node-children)) (children (cdr node-children))) (setcar next-list node) (push (cons (cons next-list children) children) queue))))) (car top))) (defun orgia-element-replace (current new destructive?) (if (eq current new) current (let* ((lst? (and (listp new) (not (symbolp (car new))))) (new-lst (if lst? (if destructive? (nconc new) (reverse new)) (list new)))) (dolist (element new-lst) (org-element-insert-before element current))) (org-element-extract-element current) new)) (defun orgia--transform-link (data) (if (not (string-equal "orgia" (org-element-property :type data))) data (let* ((path (org-element-property :path data))) (if (not (eq ?\( (aref path 0))) (or path (org-element-contents data)) (let ((tree (read path))) (dolist (f orgia-transform-functions tree) (setq tree (funcall f tree)))))))) (defun orgia-parse-tree-filter (data _backend info) (org-element-map data 'link (lambda (data) (orgia-element-replace data (orgia--transform-link data) t)) info nil nil t) data)