forked from mirrors/org-mode
Signal an error when a circular macro expansion happens
* lisp/org.el (org-macro-replace-all): Signal an error when a circular macro expansion happens. (org-macro-initialize-templates): Fix docstring. * testing/lisp/test-org.el: Add test.
This commit is contained in:
parent
1f3a2c42c6
commit
6290da183c
46
lisp/org.el
46
lisp/org.el
|
@ -20927,28 +20927,40 @@ TEMPLATES is an alist of templates used for expansion. See
|
|||
`org-macro-templates' for a buffer-local default value."
|
||||
(save-excursion
|
||||
(goto-char (point-min))
|
||||
(while (re-search-forward "{{{[-A-Za-z0-9_]" nil t)
|
||||
(let ((object (org-element-context)))
|
||||
(when (eq (org-element-type object) 'macro)
|
||||
(let ((value (org-macro-expand object templates)))
|
||||
(when value
|
||||
(delete-region
|
||||
(org-element-property :begin object)
|
||||
;; Preserve white spaces after the macro.
|
||||
(progn (goto-char (org-element-property :end object))
|
||||
(skip-chars-backward " \t")
|
||||
(point)))
|
||||
;; Leave point before replacement in case of recursive
|
||||
;; expansions.
|
||||
(save-excursion (insert value)))))))))
|
||||
(let (record)
|
||||
(while (re-search-forward "{{{[-A-Za-z0-9_]" nil t)
|
||||
(let ((object (org-element-context)))
|
||||
(when (eq (org-element-type object) 'macro)
|
||||
(let* ((value (org-macro-expand object templates))
|
||||
(begin (org-element-property :begin object))
|
||||
(signature (list begin
|
||||
object
|
||||
(org-element-property :args object))))
|
||||
;; Avoid circular dependencies by checking if the same
|
||||
;; macro with the same arguments is expanded at the same
|
||||
;; position twice.
|
||||
(if (member signature record)
|
||||
(error "Circular macro expansion: %s"
|
||||
(org-element-property :key object))
|
||||
(when value
|
||||
(push signature record)
|
||||
(delete-region
|
||||
begin
|
||||
;; Preserve white spaces after the macro.
|
||||
(progn (goto-char (org-element-property :end object))
|
||||
(skip-chars-backward " \t")
|
||||
(point)))
|
||||
;; Leave point before replacement in case of recursive
|
||||
;; expansions.
|
||||
(save-excursion (insert value)))))))))))
|
||||
|
||||
(defun org-macro-initialize-templates ()
|
||||
"Collect macro templates defined in current buffer.
|
||||
Templates are stored in buffer-local variable
|
||||
`org-macro-templates'. In addition to buffer-defined macros, the
|
||||
function installs the following ones: \"property\", \"date\",
|
||||
\"time\". and, if appropriate, \"input-file\" and
|
||||
\"modification-time\"."
|
||||
function installs the following ones: \"property\",
|
||||
\"time\". and, if the buffer is associated to a file,
|
||||
\"input-file\" and \"modification-time\"."
|
||||
(let ((case-fold-search t)
|
||||
(set-template
|
||||
(lambda (cell)
|
||||
|
|
|
@ -410,7 +410,13 @@ http://article.gmane.org/gmane.emacs.orgmode/21459/"
|
|||
"#+MACRO: in inner\n#+MACRO: out {{{in}}} outer\n{{{out}}}"
|
||||
(progn (org-macro-initialize-templates)
|
||||
(org-macro-replace-all org-macro-templates)
|
||||
(buffer-string))))))
|
||||
(buffer-string)))))
|
||||
;; Error out when macro expansion is circular.
|
||||
(should-error
|
||||
(org-test-with-temp-text
|
||||
"#+MACRO: mac1 {{{mac2}}}\n#+MACRO: mac2 {{{mac1}}}\n{{{mac1}}}"
|
||||
(org-macro-initialize-templates)
|
||||
(org-macro-replace-all org-macro-templates))))
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue