org-export: Expand correctly {{{title}}} and such

* contrib/lisp/org-export.el (org-export-as): Expand correctly
  {{{title}}} and such when they already contain a regular macro.
  This is done by expanding macros in two steps: at first regular
  macros,  then document specific macros.
(org-export-expand-macro): Remove function.
* testing/lisp/test-org-export.el: Add test.
This commit is contained in:
Nicolas Goaziou 2012-10-29 13:42:30 +01:00
parent a8c026cb26
commit a2120a9d73
2 changed files with 75 additions and 77 deletions

View File

@ -2563,49 +2563,65 @@ Return code as a string."
(goto-char (point-min))
(forward-line)
(narrow-to-region (point) (point-max))))
;; 1. Get export environment from original buffer. Also install
;; user's and developer's filters.
(let* ((info (org-export-install-filters
(org-export-get-environment backend subtreep ext-plist)))
;; 2. Get parse tree. Buffer isn't parsed directly.
;; Instead, a temporary copy is created, where include
;; keywords and macros are expanded and code blocks
;; are evaluated.
(tree (org-export-with-current-buffer-copy
(unless noexpand
(org-export-expand-include-keyword)
;; Update radio targets since keyword
;; inclusion might have added some more.
(org-update-radio-target-regexp)
(org-export-expand-macro info)
;; TODO: Setting `org-current-export-file' is
;; required by Org Babel to properly resolve
;; noweb references. Once "org-exp.el" is
;; removed, modify
;; `org-export-blocks-preprocess' so it
;; accepts the value as an argument instead.
(let ((org-current-export-file (current-buffer)))
(org-export-blocks-preprocess)))
(goto-char (point-min))
;; Run hook
;; `org-export-before-parsing-hook'. with current
;; back-end as argument.
(run-hook-with-args
'org-export-before-parsing-hook backend)
;; Eventually parse buffer.
(org-element-parse-buffer nil visible-only))))
;; 3. Call parse-tree filters to get the final tree.
(setq tree
(org-export-filter-apply-functions
(plist-get info :filter-parse-tree) tree info))
;; 4. Now tree is complete, compute its properties and add
;; them to communication channel.
;; Install user's and developer's filters in communication
;; channel.
(let (info tree)
(org-export-with-current-buffer-copy
;; Update communication channel and get parse tree. Buffer
;; isn't parsed directly. Instead, a temporary copy is
;; created, where include keywords, macros are expanded and
;; code blocks are evaluated.
(unless noexpand
(org-export-expand-include-keyword)
;; Update macro templates since #+INCLUDE keywords might
;; have added some new ones.
(org-macro-initialize-templates)
(org-macro-replace-all org-macro-templates)
;; TODO: Setting `org-current-export-file' is required by
;; Org Babel to properly resolve noweb references. Once
;; "org-exp.el" is removed, modify
;; `org-export-blocks-preprocess' so it accepts the value
;; as an argument instead.
(let ((org-current-export-file (current-buffer)))
(org-export-blocks-preprocess)))
;; Update radio targets since keyword inclusion might have
;; added some more.
(org-update-radio-target-regexp)
;; Run hook `org-export-before-parsing-hook'. with current
;; back-end as argument.
(goto-char (point-min))
(run-hook-with-args 'org-export-before-parsing-hook backend)
;; Initialize communication channel.
(setq info
(org-export-install-filters
(org-export-get-environment backend subtreep ext-plist)))
;; Expand export-specific set of macros: {{{author}}},
;; {{{date}}}, {{{email}}} and {{{title}}}. It must be done
;; once regular macros have been expanded, since document
;; keywords may contain one of them.
(unless noexpand
(org-macro-replace-all
(list (cons "author"
(org-element-interpret-data (plist-get info :author)))
(cons "date"
(org-element-interpret-data (plist-get info :date)))
;; EMAIL is not a parsed keyword: store it as-is.
(cons "email" (or (plist-get info :email) ""))
(cons "title"
(org-element-interpret-data (plist-get info :title))))))
;; Eventually parse buffer. Call parse-tree filters to get
;; the final tree.
(setq tree
(org-export-filter-apply-functions
(plist-get info :filter-parse-tree)
(org-element-parse-buffer nil visible-only) info)))
;; Now tree is complete, compute its properties and add them
;; to communication channel.
(setq info
(org-combine-plists
info (org-export-collect-tree-properties tree info)))
;; 5. Eventually transcode TREE. Wrap the resulting string
;; into a template, if required. Eventually call
;; final-output filter.
;; Eventually transcode TREE. Wrap the resulting string into
;; a template, if required. Finally call final-output filter.
(let* ((body (org-element-normalize-string (org-export-data tree info)))
(template (cdr (assq 'template
(plist-get info :translate-alist))))
@ -2742,26 +2758,6 @@ Point is at buffer's beginning when BODY is applied."
(goto-char (point-min))
(progn ,@body))))))
(defun org-export-expand-macro (info)
"Expand every macro in buffer.
INFO is a plist containing export options and buffer properties."
;; First update macro templates since #+INCLUDE keywords might have
;; added some new ones.
(org-macro-initialize-templates)
(org-macro-replace-all
;; Before expanding macros, install {{{author}}}, {{{date}}},
;; {{{email}}} and {{{title}}} templates.
(nconc
(list (cons "author"
(org-element-interpret-data (plist-get info :author)))
(cons "date"
(org-element-interpret-data (plist-get info :date)))
;; EMAIL is not a parsed keyword: store it as-is.
(cons "email" (or (plist-get info :email) ""))
(cons "title"
(org-element-interpret-data (plist-get info :title))))
org-macro-templates)))
(defun org-export-expand-include-keyword (&optional included dir)
"Expand every include keyword in buffer.
Optional argument INCLUDED is a list of included file names along

View File

@ -439,13 +439,12 @@ body\n")))
"Test macro expansion in an Org buffer."
;; Standard macro expansion.
(should
(equal "#+MACRO: macro1 value\nvalue"
(equal "#+MACRO: macro1 value\nvalue\n"
(org-test-with-temp-text "#+MACRO: macro1 value\n{{{macro1}}}"
(let (info)
(org-export-expand-macro info) (buffer-string)))))
;; Export specific macros.
(org-test-with-backend test (org-export-as 'test)))))
;; Expand specific macros.
(should
(equal "me 2012-03-29 me@here Title"
(equal "me 2012-03-29 me@here Title\n"
(org-test-with-temp-text
"
#+TITLE: Title
@ -453,23 +452,26 @@ body\n")))
#+AUTHOR: me
#+EMAIL: me@here
{{{author}}} {{{date}}} {{{email}}} {{{title}}}"
(let ((info (org-export-get-environment)))
(org-export-expand-macro info)
(goto-char (point-max))
(buffer-substring (line-beginning-position)
(line-end-position))))))
(let ((output (org-test-with-backend test (org-export-as 'test))))
(substring output (string-match ".*\n\\'" output))))))
;; Expand specific macros when property contained a regular macro
;; already.
(should
(equal "value\n"
(org-test-with-temp-text "
#+MACRO: macro1 value
#+TITLE: {{{macro1}}}
{{{title}}}"
(let ((output (org-test-with-backend test (org-export-as 'test))))
(substring output (string-match ".*\n\\'" output))))))
;; Expand macros with templates in included files.
(should
(equal "success"
(equal "success\n"
(org-test-with-temp-text
(format "#+INCLUDE: \"%s/examples/macro-templates.org\"
{{{included-macro}}}" org-test-dir)
(let (info)
(org-export-expand-include-keyword)
(org-export-expand-macro info)
(goto-char (point-max))
(buffer-substring (line-beginning-position)
(line-end-position)))))))
(let ((output (org-test-with-backend test (org-export-as 'test))))
(substring output (string-match ".*\n\\'" output)))))))
(ert-deftest test-org-export/user-ignore-list ()
"Test if `:ignore-list' accepts user input."