summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Goaziou <n.goaziou@gmail.com>2012-10-06 10:27:57 +0200
committerNicolas Goaziou <n.goaziou@gmail.com>2012-10-06 10:29:37 +0200
commit58b42debb18f8988cae7358642cbdc0287e3f2a5 (patch)
tree20e1c89664b2203e9c425cd22c76448f2bdfe8da
parent0af2f6068f48f09c4e6feb26e0a72dff869ec7ea (diff)
downloadorg-mode-58b42debb18f8988cae7358642cbdc0287e3f2a5.tar.gz
org-export: Include title, author, date and email macros
* contrib/lisp/org-export.el (org-export-expand-macro): New function. (org-export-as): Use new function. * lisp/org.el (org-macro-expand, org-macro-replace-all): Change signature. The function now accepts an alist of templates so it doesn't have to rely only on `org-macro-templates'. (org-macro-initialize-templates): {{{date}}} is not anymore an alias for {{{time}}}. During export, it will provide the value stored in DATE keyword instead. * testing/lisp/test-org-export.el: Add tests. * testing/lisp/test-org.el: Update tests.
-rw-r--r--contrib/lisp/org-export.el75
-rw-r--r--lisp/org.el33
-rw-r--r--testing/lisp/test-org-export.el26
-rw-r--r--testing/lisp/test-org.el8
4 files changed, 98 insertions, 44 deletions
diff --git a/contrib/lisp/org-export.el b/contrib/lisp/org-export.el
index 3ef882f..b1b5f9a 100644
--- a/contrib/lisp/org-export.el
+++ b/contrib/lisp/org-export.el
@@ -2498,6 +2498,8 @@ Return the updated communication channel."
;; was within an item, the item should contain the headline. That's
;; why file inclusion should be done before any structure can be
;; associated to the file, that is before parsing.
+;;
+;; Macro are expanded with `org-export-expand-macro'.
(defun org-export-as
(backend &optional subtreep visible-only body-only ext-plist noexpand)
@@ -2542,34 +2544,34 @@ Return code as a string."
(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 macros
- ;; and include keywords are expanded and code blocks
- ;; are evaluated.
- (tree (let ((buf (or (buffer-file-name (buffer-base-buffer))
- (current-buffer))))
- (org-export-with-current-buffer-copy
- (unless noexpand
- (org-macro-replace-all)
- (org-export-expand-include-keyword)
- ;; 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 buf))
- (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)))))
+ (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 macros
+ ;; and include keywords are expanded and code blocks
+ ;; are evaluated.
+ (tree (let ((buf (or (buffer-file-name (buffer-base-buffer))
+ (current-buffer))))
+ (org-export-with-current-buffer-copy
+ (unless noexpand
+ (org-export-expand-macro info)
+ (org-export-expand-include-keyword)
+ ;; 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 buf))
+ (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
@@ -2721,6 +2723,23 @@ Point is at buffer's beginning when BODY is applied."
(progn ,@body))))))
(def-edebug-spec org-export-with-current-buffer-copy (body))
+(defun org-export-expand-macro (info)
+ "Expand every macro in buffer.
+INFO is a plist containing export options and buffer properties."
+ (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
diff --git a/lisp/org.el b/lisp/org.el
index cdc9ff5..efbdea2 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -20825,10 +20825,18 @@ hierarchy of headlines by UP levels before marking the subtree."
;; Macros are expanded with `org-macro-replace-all', which relies
;; internally on `org-macro-expand'.
-;; Templates for expansion are stored in the buffer-local variable
-;; `org-macro-templates'. This variable is updated by
+;; Default templates for expansion are stored in the buffer-local
+;; variable `org-macro-templates'. This variable is updated by
;; `org-macro-initialize-templates'.
+;; Along with macros defined through #+MACRO: keyword, default
+;; templates include the following hard-coded macros:
+;; {{{time(format-string)}}}, {{{property(node-property)}}},
+;; {{{input-file}}} and {{{modification-time(format-string)}}}.
+
+;; During export, {{{author}}}, {{{date}}}, {{{email}}} and
+;; {{{title}}} will also be provided.
+
(defvar org-macro-templates nil
"Alist containing all macro templates in current buffer.
@@ -20840,15 +20848,15 @@ directly, use instead:
#+MACRO: name template")
(make-variable-buffer-local 'org-macro-templates)
-(defun org-macro-expand (macro)
+(defun org-macro-expand (macro templates)
"Return expanded MACRO, as a string.
MACRO is an object, obtained, for example, with
-`org-element-context'. Return nil if no template was found."
+`org-element-context'. TEMPLATES is an alist of templates used
+for expansion. See `org-macro-templates' for a buffer-local
+default value. Return nil if no template was found."
(let ((template
- (cdr (assoc-string (org-element-property :key macro)
- org-macro-templates
- ;; Macro names are case-insensitive.
- t))))
+ ;; Macro names are case-insensitive.
+ (cdr (assoc-string (org-element-property :key macro) templates t))))
(when template
(let ((value (replace-regexp-in-string
"\\$[0-9]+"
@@ -20865,14 +20873,16 @@ MACRO is an object, obtained, for example, with
;; Return string.
(format "%s" (or value ""))))))
-(defun org-macro-replace-all ()
- "Replace all macros in current buffer by their expansion."
+(defun org-macro-replace-all (templates)
+ "Replace all macros in current buffer by their expansion.
+TEMPLATES is an alist of templates used for expansion. See
+`org-macro-templates' for a buffer-local default value."
(save-excursion
(goto-char (point-min))
(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)))
+ (let ((value (org-macro-expand object templates)))
(when value
(delete-region
(org-element-property :begin object)
@@ -20916,7 +20926,6 @@ function installs the following ones: \"property\", \"date\",
(mapc (lambda (cell) (funcall set-template cell))
(list
(cons "property" "(eval (org-entry-get nil \"$1\" 'selective))")
- (cons "date" "(eval (format-time-string \"$1\"))")
(cons "time" "(eval (format-time-string \"$1\"))")))
(let ((visited-file (buffer-file-name (buffer-base-buffer))))
(when (and visited-file (file-exists-p visited-file))
diff --git a/testing/lisp/test-org-export.el b/testing/lisp/test-org-export.el
index 0cba76a..b8463fb 100644
--- a/testing/lisp/test-org-export.el
+++ b/testing/lisp/test-org-export.el
@@ -429,6 +429,32 @@ body\n")))
(should (equal (buffer-string)
"#+BEGIN_SRC emacs-lisp\n(+ 2 1)\n#+END_SRC\n"))))
+(ert-deftest test-org-export/expand-macro ()
+ "Test macro expansion in an Org buffer."
+ ;; Standard macro expansion.
+ (should
+ (equal "#+MACRO: macro1 value\nvalue"
+ (org-test-with-temp-text "#+MACRO: macro1 value\n{{{macro1}}}"
+ (let (info)
+ (org-macro-initialize-templates)
+ (org-export-expand-macro info) (buffer-string)))))
+ ;; Export specific macros.
+ (should
+ (equal "me 2012-03-29 me@here Title"
+ (org-test-with-temp-text
+ "
+#+TITLE: Title
+#+DATE: 2012-03-29
+#+AUTHOR: me
+#+EMAIL: me@here
+{{{author}}} {{{date}}} {{{email}}} {{{title}}}"
+ (let ((info (org-export-get-environment)))
+ (org-macro-initialize-templates)
+ (org-export-expand-macro info)
+ (goto-char (point-max))
+ (buffer-substring (line-beginning-position)
+ (line-end-position)))))))
+
(ert-deftest test-org-export/user-ignore-list ()
"Test if `:ignore-list' accepts user input."
(org-test-with-backend test
diff --git a/testing/lisp/test-org.el b/testing/lisp/test-org.el
index a2f696b..cadea61 100644
--- a/testing/lisp/test-org.el
+++ b/testing/lisp/test-org.el
@@ -140,7 +140,7 @@ http://article.gmane.org/gmane.emacs.orgmode/21459/"
"#+MACRO: A B\n1 B 3"
(org-test-with-temp-text "#+MACRO: A B\n1 {{{A}}} 3"
(progn (org-macro-initialize-templates)
- (org-macro-replace-all)
+ (org-macro-replace-all org-macro-templates)
(buffer-string)))))
;; Macro with arguments.
(should
@@ -148,7 +148,7 @@ http://article.gmane.org/gmane.emacs.orgmode/21459/"
"#+MACRO: macro $1 $2\nsome text"
(org-test-with-temp-text "#+MACRO: macro $1 $2\n{{{macro(some,text)}}}"
(progn (org-macro-initialize-templates)
- (org-macro-replace-all)
+ (org-macro-replace-all org-macro-templates)
(buffer-string)))))
;; Macro with "eval".
(should
@@ -156,7 +156,7 @@ http://article.gmane.org/gmane.emacs.orgmode/21459/"
"#+MACRO: add (eval (+ $1 $2))\n3"
(org-test-with-temp-text "#+MACRO: add (eval (+ $1 $2))\n{{{add(1,2)}}}"
(progn (org-macro-initialize-templates)
- (org-macro-replace-all)
+ (org-macro-replace-all org-macro-templates)
(buffer-string)))))
;; Nested macros.
(should
@@ -165,7 +165,7 @@ http://article.gmane.org/gmane.emacs.orgmode/21459/"
(org-test-with-temp-text
"#+MACRO: in inner\n#+MACRO: out {{{in}}} outer\n{{{out}}}"
(progn (org-macro-initialize-templates)
- (org-macro-replace-all)
+ (org-macro-replace-all org-macro-templates)
(buffer-string))))))