org-export: Fix macro expansion when back-end protects dollar signs
* contrib/lisp/org-export.el (org-export-get-inbuffer-options): Return an "eval" macro as a regular secondary string instead of a plain string. (org-export-expand-macro): Replace arguments before exporting them (and possibly protecting dollar signs). Refactor code. * testing/lisp/test-org-export.el: Add tests.
This commit is contained in:
parent
368a7f69c4
commit
c91bcb368f
|
@ -1181,9 +1181,9 @@ Assume buffer is in Org mode. Narrowing, if any, is ignored."
|
|||
(value (org-match-string-no-properties 2 val)))
|
||||
(cond
|
||||
((not value) nil)
|
||||
;; Value will be evaled. Leave it as-is.
|
||||
;; Value will be evaled: do not parse it.
|
||||
((string-match "\\`(eval\\>" value)
|
||||
(list key value))
|
||||
(list key (list value)))
|
||||
;; Value has to be parsed for nested
|
||||
;; macros.
|
||||
(t
|
||||
|
@ -3033,19 +3033,21 @@ INFO is a plist holding export options."
|
|||
(let* ((key (org-element-property :key macro))
|
||||
(args (org-element-property :args macro))
|
||||
;; User's macros are stored in the communication channel with
|
||||
;; a ":macro-" prefix.
|
||||
;; a ":macro-" prefix. Replace arguments in VALUE. Also
|
||||
;; expand recursively macros within.
|
||||
(value (org-export-data
|
||||
(plist-get info (intern (format ":macro-%s" key))) info)))
|
||||
;; Replace arguments in VALUE.
|
||||
(let ((s 0) n)
|
||||
(while (string-match "\\$\\([0-9]+\\)" value s)
|
||||
(setq s (1+ (match-beginning 0))
|
||||
n (string-to-number (match-string 1 value)))
|
||||
(and (>= (length args) n)
|
||||
(setq value (replace-match (nth (1- n) args) t t value)))))
|
||||
(mapcar
|
||||
(lambda (obj)
|
||||
(if (not (stringp obj)) (org-export-data obj info)
|
||||
(replace-regexp-in-string
|
||||
"\\$[0-9]+"
|
||||
(lambda (arg)
|
||||
(nth (1- (string-to-number (substring arg 1))) args))
|
||||
obj)))
|
||||
(plist-get info (intern (format ":macro-%s" key))))
|
||||
info)))
|
||||
;; VALUE starts with "(eval": it is a s-exp, `eval' it.
|
||||
(when (string-match "\\`(eval\\>" value)
|
||||
(setq value (eval (read value))))
|
||||
(when (string-match "\\`(eval\\>" value) (setq value (eval (read value))))
|
||||
;; Return string.
|
||||
(format "%s" (or value ""))))
|
||||
|
||||
|
|
|
@ -59,7 +59,8 @@ already filled in `info'."
|
|||
(declare (debug (form body)) (indent 1))
|
||||
`(org-test-with-temp-text ,data
|
||||
(let* ((tree (org-element-parse-buffer))
|
||||
(info (org-export-collect-tree-properties tree nil)))
|
||||
(info (org-export-collect-tree-properties
|
||||
tree (org-export-get-environment))))
|
||||
,@body)))
|
||||
|
||||
(ert-deftest test-org-export/parse-option-keyword ()
|
||||
|
@ -111,38 +112,6 @@ already filled in `info'."
|
|||
:exclude-tags ("noexport" "invisible") :keywords "test" :language "en"
|
||||
:select-tags ("export") :title ("Some title with spaces")))))
|
||||
|
||||
(ert-deftest test-org-export/define-macro ()
|
||||
"Try defining various Org macro using in-buffer #+MACRO: keyword."
|
||||
;; Parsed macro.
|
||||
(should (equal (org-test-with-temp-text "#+MACRO: one 1"
|
||||
(org-export-get-inbuffer-options))
|
||||
'(:macro-one ("1"))))
|
||||
;; Evaled macro.
|
||||
(should (equal (org-test-with-temp-text "#+MACRO: two (eval (+ 1 1))"
|
||||
(org-export-get-inbuffer-options))
|
||||
'(:macro-two "(eval (+ 1 1))")))
|
||||
;; Incomplete macro.
|
||||
(should-not (org-test-with-temp-text "#+MACRO: three"
|
||||
(org-export-get-inbuffer-options)))
|
||||
;; Macro with newline character.
|
||||
(should (equal (org-test-with-temp-text "#+MACRO: four a\\nb"
|
||||
(org-export-get-inbuffer-options))
|
||||
'(:macro-four ("a\nb"))))
|
||||
;; Macro with protected newline character.
|
||||
(should (equal (org-test-with-temp-text "#+MACRO: five a\\\\nb"
|
||||
(org-export-get-inbuffer-options))
|
||||
'(:macro-five ("a\\nb"))))
|
||||
;; Recursive macro.
|
||||
(org-test-with-temp-text "#+MACRO: six 6\n#+MACRO: seven 1 + {{{six}}}"
|
||||
(should
|
||||
(equal
|
||||
(org-export-get-inbuffer-options)
|
||||
'(:macro-six
|
||||
("6")
|
||||
:macro-seven
|
||||
("1 + " (macro (:key "six" :value "{{{six}}}" :args nil :begin 5 :end 14
|
||||
:post-blank 0))))))))
|
||||
|
||||
(ert-deftest test-org-export/handle-options ()
|
||||
"Test if export options have an impact on output."
|
||||
;; Test exclude tags.
|
||||
|
@ -544,7 +513,7 @@ Paragraph[1][2][fn:lbl3:C<<target>>][[test]][[target]]\n[1] A\n\n[2] <<test>>B"
|
|||
(org-export-get-ordinal
|
||||
(org-export-resolve-fuzzy-link link info) info)) info t)))))
|
||||
|
||||
(defun test-org-export/resolve-coderef ()
|
||||
(ert-deftest test-org-export/resolve-coderef ()
|
||||
"Test `org-export-resolve-coderef' specifications."
|
||||
(let ((org-coderef-label-format "(ref:%s)"))
|
||||
;; 1. A link to a "-n -k -r" block returns line number.
|
||||
|
@ -659,6 +628,78 @@ Another text. (ref:text)
|
|||
info)))))
|
||||
|
||||
|
||||
|
||||
;;; Macro
|
||||
|
||||
(ert-deftest test-org-export/define-macro ()
|
||||
"Try defining various Org macro using in-buffer #+MACRO: keyword."
|
||||
;; Parsed macro.
|
||||
(should (equal (org-test-with-temp-text "#+MACRO: one 1"
|
||||
(org-export-get-inbuffer-options))
|
||||
'(:macro-one ("1"))))
|
||||
;; Evaled macro.
|
||||
(should (equal (org-test-with-temp-text "#+MACRO: two (eval (+ 1 1))"
|
||||
(org-export-get-inbuffer-options))
|
||||
'(:macro-two ("(eval (+ 1 1))"))))
|
||||
;; Incomplete macro.
|
||||
(should-not (org-test-with-temp-text "#+MACRO: three"
|
||||
(org-export-get-inbuffer-options)))
|
||||
;; Macro with newline character.
|
||||
(should (equal (org-test-with-temp-text "#+MACRO: four a\\nb"
|
||||
(org-export-get-inbuffer-options))
|
||||
'(:macro-four ("a\nb"))))
|
||||
;; Macro with protected newline character.
|
||||
(should (equal (org-test-with-temp-text "#+MACRO: five a\\\\nb"
|
||||
(org-export-get-inbuffer-options))
|
||||
'(:macro-five ("a\\nb"))))
|
||||
;; Recursive macro.
|
||||
(org-test-with-temp-text "#+MACRO: six 6\n#+MACRO: seven 1 + {{{six}}}"
|
||||
(should
|
||||
(equal
|
||||
(org-export-get-inbuffer-options)
|
||||
'(:macro-six
|
||||
("6")
|
||||
:macro-seven
|
||||
("1 + " (macro (:key "six" :value "{{{six}}}" :args nil :begin 5 :end 14
|
||||
:post-blank 0))))))))
|
||||
|
||||
(ert-deftest test-org-export/expand-macro ()
|
||||
"Test `org-export-expand-macro' specifications."
|
||||
;; Standard test.
|
||||
(should
|
||||
(equal
|
||||
"some text"
|
||||
(org-test-with-parsed-data "#+MACRO: macro some text\n{{{macro}}}"
|
||||
(org-export-expand-macro
|
||||
(org-element-map tree 'macro 'identity info t) info))))
|
||||
;; Macro with arguments.
|
||||
(should
|
||||
(equal
|
||||
"some text"
|
||||
(org-test-with-parsed-data "#+MACRO: macro $1 $2\n{{{macro(some,text)}}}"
|
||||
(org-export-expand-macro
|
||||
(org-element-map tree 'macro 'identity info t) info))))
|
||||
;; Macro with "eval"
|
||||
(should
|
||||
(equal
|
||||
"3"
|
||||
(org-test-with-parsed-data "#+MACRO: add (eval (+ $1 $2))\n{{{add(1,2)}}}"
|
||||
(org-export-expand-macro
|
||||
(org-element-map tree 'macro 'identity info t) info))))
|
||||
;; Nested macros.
|
||||
(should
|
||||
(equal
|
||||
"inner outer"
|
||||
(org-test-with-parsed-data
|
||||
"#+MACRO: in inner\n#+MACRO: out {{{in}}} outer\n{{{out}}}"
|
||||
(flet ((translate-macro (macro contents info)
|
||||
(org-export-expand-macro macro info)))
|
||||
(org-export-expand-macro
|
||||
(org-element-map tree 'macro 'identity info t)
|
||||
(org-combine-plists
|
||||
info `(:translate-alist ((macro . translate-macro))))))))))
|
||||
|
||||
|
||||
|
||||
;;; Src-block and example-block
|
||||
|
||||
|
|
Loading…
Reference in New Issue