Browse Source

org-macro: Allow macros in parsed keywords and associated properties

* lisp/org-macro.el (org-macro-replace-all): Add optional argument.
  Now accept macros in parsed keywords and associated properties.

* lisp/ox.el (org-export-as): Apply signature change.

* testing/lisp/test-ox.el (test-org-export/expand-macro): Add test.
Nicolas Goaziou 10 years ago
parent
commit
fa64b59b05
3 changed files with 70 additions and 27 deletions
  1. 43 25
      lisp/org-macro.el
  2. 8 2
      lisp/ox.el
  3. 19 0
      testing/lisp/test-ox.el

+ 43 - 25
lisp/org-macro.el

@@ -159,7 +159,7 @@ default value.  Return nil if no template was found."
         ;; Return string.
         ;; Return string.
         (format "%s" (or value ""))))))
         (format "%s" (or value ""))))))
 
 
-(defun org-macro-replace-all (templates &optional finalize)
+(defun org-macro-replace-all (templates &optional finalize keywords)
   "Replace all macros in current buffer by their expansion.
   "Replace all macros in current buffer by their expansion.
 
 
 TEMPLATES is an alist of templates used for expansion.  See
 TEMPLATES is an alist of templates used for expansion.  See
@@ -169,35 +169,53 @@ If optional arg FINALIZE is non-nil, raise an error if a macro is
 found in the buffer with no definition in TEMPLATES."
 found in the buffer with no definition in TEMPLATES."
   (save-excursion
   (save-excursion
     (goto-char (point-min))
     (goto-char (point-min))
-    (let (record)
+    (let ((properties-regexp
+	   (format "\\`EXPORT_%s\\+?\\'" (regexp-opt keywords)))
+	  record)
       (while (re-search-forward "{{{[-A-Za-z0-9_]" nil t)
       (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))
+	(let* ((datum (save-match-data (org-element-context)))
+	       (type (org-element-type datum))
+	       (macro
+		(cond
+		 ((eq type 'macro) datum)
+		 ;; In parsed keywords and associated node properties,
+		 ;; force macro recognition.
+		 ((or (and (eq type 'keyword)
+			   (member (org-element-property :key datum) keywords))
+		      (and (eq type 'node-property)
+			   (org-string-match-p
+			    properties-regexp
+			    (org-element-property :key datum))))
+		  (save-restriction
+		    (narrow-to-region (match-beginning 0) (line-end-position))
+		    (org-element-map (org-element-parse-buffer) 'macro
+		      #'identity nil t))))))
+	  (when macro
+	    (let* ((value (org-macro-expand macro templates))
+		   (begin (org-element-property :begin macro))
 		   (signature (list begin
 		   (signature (list begin
-				    object
-				    (org-element-property :args object))))
+				    macro
+				    (org-element-property :args macro))))
 	      ;; Avoid circular dependencies by checking if the same
 	      ;; Avoid circular dependencies by checking if the same
 	      ;; macro with the same arguments is expanded at the same
 	      ;; macro with the same arguments is expanded at the same
 	      ;; position twice.
 	      ;; position twice.
-	      (if (member signature record)
-		  (error "Circular macro expansion: %s"
-			 (org-element-property :key object))
-		(cond (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)))
-		      (finalize
-		       (error "Undefined Org macro: %s; aborting"
-			      (org-element-property :key object))))))))))))
+	      (cond ((member signature record)
+		     (error "Circular macro expansion: %s"
+			    (org-element-property :key macro)))
+		    (value
+		     (push signature record)
+		     (delete-region
+		      begin
+		      ;; Preserve white spaces after the macro.
+		      (progn (goto-char (org-element-property :end macro))
+			     (skip-chars-backward " \t")
+			     (point)))
+		     ;; Leave point before replacement in case of
+		     ;; recursive expansions.
+		     (save-excursion (insert value)))
+		    (finalize
+		     (error "Undefined Org macro: %s; aborting"
+			    (org-element-property :key macro)))))))))))
 
 
 (defun org-macro-escape-arguments (&rest args)
 (defun org-macro-escape-arguments (&rest args)
   "Build macro's arguments string from ARGS.
   "Build macro's arguments string from ARGS.

+ 8 - 2
lisp/ox.el

@@ -2850,6 +2850,11 @@ Return code as a string."
 				      (and visible-only 'visible-only)
 				      (and visible-only 'visible-only)
 				      (and body-only 'body-only))))
 				      (and body-only 'body-only))))
 		    (org-export--get-buffer-attributes)))
 		    (org-export--get-buffer-attributes)))
+	     (parsed-keywords
+	      (delq nil
+		    (mapcar (lambda (o) (and (eq (nth 4 o) 'parse) (nth 1 o)))
+			    (append (org-export-get-all-options backend)
+				    org-export-options-alist))))
 	     tree)
 	     tree)
 	;; Update communication channel and get parse tree.  Buffer
 	;; Update communication channel and get parse tree.  Buffer
 	;; isn't parsed directly.  Instead, a temporary copy is
 	;; isn't parsed directly.  Instead, a temporary copy is
@@ -2864,7 +2869,7 @@ Return code as a string."
 	 ;; Update macro templates since #+INCLUDE keywords might have
 	 ;; Update macro templates since #+INCLUDE keywords might have
 	 ;; added some new ones.
 	 ;; added some new ones.
 	 (org-macro-initialize-templates)
 	 (org-macro-initialize-templates)
-	 (org-macro-replace-all org-macro-templates)
+	 (org-macro-replace-all org-macro-templates nil parsed-keywords)
 	 (org-export-execute-babel-code)
 	 (org-export-execute-babel-code)
 	 ;; Update radio targets since keyword inclusion might have
 	 ;; Update radio targets since keyword inclusion might have
 	 ;; added some more.
 	 ;; added some more.
@@ -2908,7 +2913,8 @@ Return code as a string."
 	   (cons "email" (org-element-interpret-data (plist-get info :email)))
 	   (cons "email" (org-element-interpret-data (plist-get info :email)))
 	   (cons "title" (org-element-interpret-data (plist-get info :title)))
 	   (cons "title" (org-element-interpret-data (plist-get info :title)))
 	   (cons "results" "$1"))
 	   (cons "results" "$1"))
-	  'finalize)
+	  'finalize
+	  parsed-keywords)
 	 ;; Parse buffer.
 	 ;; Parse buffer.
 	 (setq tree (org-element-parse-buffer nil visible-only))
 	 (setq tree (org-element-parse-buffer nil visible-only))
 	 ;; Prune tree from non-exported elements and transform
 	 ;; Prune tree from non-exported elements and transform

+ 19 - 0
testing/lisp/test-ox.el

@@ -1091,6 +1091,25 @@ Footnotes[fn:2], foot[fn:test], digit only[3], and [fn:inline:anonymous footnote
    (equal "#+MACRO: macro1 value\nvalue\n"
    (equal "#+MACRO: macro1 value\nvalue\n"
 	  (org-test-with-temp-text "#+MACRO: macro1 value\n{{{macro1}}}"
 	  (org-test-with-temp-text "#+MACRO: macro1 value\n{{{macro1}}}"
 	    (org-export-as (org-test-default-backend)))))
 	    (org-export-as (org-test-default-backend)))))
+  ;; Allow macro in parsed keywords and associated properties.
+  ;; Standard macro expansion.
+  (should
+   (string-match
+    "#\\+K: value"
+    (let ((backend (org-export-create-backend
+		    :parent 'org
+		    :options '((:k "K" nil nil parse)))))
+      (org-test-with-temp-text "#+MACRO: macro value\n#+K: {{{macro}}}"
+	(org-export-as backend)))))
+  (should
+   (string-match
+    ":EXPORT_K: v"
+    (let ((backend (org-export-create-backend
+		    :parent 'org
+		    :options '((:k "K" nil nil parse)))))
+      (org-test-with-temp-text
+	  "#+MACRO: m v\n* H\n:PROPERTIES:\n:EXPORT_K: {{{m}}}\n:END:"
+	(org-export-as backend nil nil nil '(:with-properties t))))))
   ;; Expand specific macros.
   ;; Expand specific macros.
   (should
   (should
    (equal "me 2012-03-29 me@here Title\n"
    (equal "me 2012-03-29 me@here Title\n"