summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Goaziou <n.goaziou@gmail.com>2012-05-20 11:53:39 +0200
committerNicolas Goaziou <n.goaziou@gmail.com>2012-05-20 12:18:16 +0200
commitc91bcb368f0ec483467da9cbe607eb89ac505f5b (patch)
tree27e33396a3d7d7eb5bc5a89d7d23f2ff27e9685a
parent368a7f69c4e02ee046061c7bc26f65c7dd5b9cdf (diff)
downloadorg-mode-c91bcb368f0ec483467da9cbe607eb89ac505f5b.tar.gz
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.
-rw-r--r--contrib/lisp/org-export.el28
-rw-r--r--testing/lisp/test-org-export.el109
2 files changed, 90 insertions, 47 deletions
diff --git a/contrib/lisp/org-export.el b/contrib/lisp/org-export.el
index a5edc0a..abd3e1d 100644
--- a/contrib/lisp/org-export.el
+++ b/contrib/lisp/org-export.el
@@ -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 ""))))
diff --git a/testing/lisp/test-org-export.el b/testing/lisp/test-org-export.el
index 5075c87..78a6b08 100644
--- a/testing/lisp/test-org-export.el
+++ b/testing/lisp/test-org-export.el
@@ -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.
@@ -660,6 +629,78 @@ Another text. (ref:text)
+;;; 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
(ert-deftest test-org-export/unravel-code ()