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:
Nicolas Goaziou 2012-05-20 11:53:39 +02:00
parent 368a7f69c4
commit c91bcb368f
2 changed files with 90 additions and 47 deletions

View File

@ -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 ""))))

View File

@ -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