Browse Source

org-export: Remove naming convening for back-ends

* contrib/lisp/org-e-ascii.el (org-e-ascii-translate-alist): New variable.
* contrib/lisp/org-e-html.el (org-e-html-translate-alist): New
  variable.
(org-e-html-filters-alist): Move variable into an appropriate section.
* contrib/lisp/org-e-latex.el (org-e-latex-translate-alist): New variable.
* contrib/lisp/org-e-odt.el (org-e-odt-translate-alist): New variable.
(org-e-odt-option-alist): Move variable into an appropriate section.
* contrib/lisp/org-export.el (org-export-transcoder): Retrieve
  translators from `org-BACKEND-translate-alist' instead of applying
  a naming convention to each of them.
* testing/lisp/test-org-export.el: Update tests.
Nicolas Goaziou 13 years ago
parent
commit
7421e96536

+ 64 - 5
contrib/lisp/org-e-ascii.el

@@ -67,23 +67,78 @@
  (backend file &optional subtreep visible-only body-only ext-plist))
 
 
-
-;;; Internal Variables
-
+;;; Define Back-End
+;;
 ;; The following setting won't allow to modify preferred charset
 ;; through a buffer keyword or an option item, but, since the property
 ;; will appear in communication channel nonetheless, it allows to
 ;; override `org-e-ascii-charset' variable on the fly by the ext-plist
 ;; mechanism.
-
+;;
 ;; We also install a filter for headlines and sections, in order to
 ;; control blank lines separating them in output string.
 
+(defvar org-e-ascii-translate-alist
+  '((babel-call . org-e-ascii-babel-call)
+    (bold . org-e-ascii-bold)
+    (center-block . org-e-ascii-center-block)
+    (clock . org-e-ascii-clock)
+    (code . org-e-ascii-code)
+    (comment . org-e-ascii-comment)
+    (comment-block . org-e-ascii-comment-block)
+    (drawer . org-e-ascii-drawer)
+    (dynamic-block . org-e-ascii-dynamic-block)
+    (entity . org-e-ascii-entity)
+    (example-block . org-e-ascii-example-block)
+    (export-block . org-e-ascii-export-block)
+    (export-snippet . org-e-ascii-export-snippet)
+    (fixed-width . org-e-ascii-fixed-width)
+    (footnote-definition . org-e-ascii-footnote-definition)
+    (footnote-reference . org-e-ascii-footnote-reference)
+    (headline . org-e-ascii-headline)
+    (horizontal-rule . org-e-ascii-horizontal-rule)
+    (inline-babel-call . org-e-ascii-inline-babel-call)
+    (inline-src-block . org-e-ascii-inline-src-block)
+    (inlinetask . org-e-ascii-inlinetask)
+    (italic . org-e-ascii-italic)
+    (item . org-e-ascii-item)
+    (keyword . org-e-ascii-keyword)
+    (latex-environment . org-e-ascii-latex-environment)
+    (latex-fragment . org-e-ascii-latex-fragment)
+    (line-break . org-e-ascii-line-break)
+    (link . org-e-ascii-link)
+    (macro . org-e-ascii-macro)
+    (paragraph . org-e-ascii-paragraph)
+    (plain-list . org-e-ascii-plain-list)
+    (plain-text . org-e-ascii-plain-text)
+    (planning . org-e-ascii-planning)
+    (property-drawer . org-e-ascii-property-drawer)
+    (quote-block . org-e-ascii-quote-block)
+    (quote-section . org-e-ascii-quote-section)
+    (radio-target . org-e-ascii-radio-target)
+    (section . org-e-ascii-section)
+    (special-block . org-e-ascii-special-block)
+    (src-block . org-e-ascii-src-block)
+    (statistics-cookie . org-e-ascii-statistics-cookie)
+    (strike-through . org-e-ascii-strike-through)
+    (subscript . org-e-ascii-subscript)
+    (superscript . org-e-ascii-superscript)
+    (table . org-e-ascii-table)
+    (table-cell . org-e-ascii-table-cell)
+    (table-row . org-e-ascii-table-row)
+    (target . org-e-ascii-target)
+    (template . org-e-ascii-template)
+    (timestamp . org-e-ascii-timestamp)
+    (underline . org-e-ascii-underline)
+    (verbatim . org-e-ascii-verbatim)
+    (verse-block . org-e-ascii-verse-block))
+  "Alist between element or object types and translators.")
+
 (defconst org-e-ascii-option-alist
   '((:ascii-charset nil nil org-e-ascii-charset))
   "Alist between ASCII export properties and ways to set them.
 See `org-export-option-alist' for more information on the
-structure or the values.")
+structure of the values.")
 
 (defconst org-e-ascii-filters-alist
   '((:filter-headline . org-e-ascii-filter-headline-blank-lines)
@@ -91,6 +146,10 @@ structure or the values.")
   "Alist between filters keywords and back-end specific filters.
 See `org-export-filters-alist' for more information.")
 
+
+
+;;; Internal Variables
+
 (defconst org-e-ascii-dictionary
   '(("Footnotes\n"
      ("en"

+ 69 - 38
contrib/lisp/org-e-html.el

@@ -85,9 +85,63 @@
 		  "org-compat" (&optional buffer-or-name norecord label))
 
 
-
-
-;;; Internal Variables
+;;; Define Back-End
+
+(defvar org-e-html-translate-alist
+  '((babel-call . org-e-html-babel-call)
+    (bold . org-e-html-bold)
+    (center-block . org-e-html-center-block)
+    (clock . org-e-html-clock)
+    (code . org-e-html-code)
+    (comment . org-e-html-comment)
+    (comment-block . org-e-html-comment-block)
+    (drawer . org-e-html-drawer)
+    (dynamic-block . org-e-html-dynamic-block)
+    (entity . org-e-html-entity)
+    (example-block . org-e-html-example-block)
+    (export-block . org-e-html-export-block)
+    (export-snippet . org-e-html-export-snippet)
+    (fixed-width . org-e-html-fixed-width)
+    (footnote-definition . org-e-html-footnote-definition)
+    (footnote-reference . org-e-html-footnote-reference)
+    (headline . org-e-html-headline)
+    (horizontal-rule . org-e-html-horizontal-rule)
+    (inline-babel-call . org-e-html-inline-babel-call)
+    (inline-src-block . org-e-html-inline-src-block)
+    (inlinetask . org-e-html-inlinetask)
+    (italic . org-e-html-italic)
+    (item . org-e-html-item)
+    (keyword . org-e-html-keyword)
+    (latex-environment . org-e-html-latex-environment)
+    (latex-fragment . org-e-html-latex-fragment)
+    (line-break . org-e-html-line-break)
+    (link . org-e-html-link)
+    (macro . org-e-html-macro)
+    (paragraph . org-e-html-paragraph)
+    (plain-list . org-e-html-plain-list)
+    (plain-text . org-e-html-plain-text)
+    (planning . org-e-html-planning)
+    (property-drawer . org-e-html-property-drawer)
+    (quote-block . org-e-html-quote-block)
+    (quote-section . org-e-html-quote-section)
+    (radio-target . org-e-html-radio-target)
+    (section . org-e-html-section)
+    (special-block . org-e-html-special-block)
+    (src-block . org-e-html-src-block)
+    (statistics-cookie . org-e-html-statistics-cookie)
+    (strike-through . org-e-html-strike-through)
+    (subscript . org-e-html-subscript)
+    (superscript . org-e-html-superscript)
+    (table . org-e-html-table)
+    (table-cell . org-e-html-table-cell)
+    (table-row . org-e-html-table-row)
+    (target . org-e-html-target)
+    (template . org-e-html-template)
+    (timestamp . org-e-html-timestamp)
+    (underline . org-e-html-underline)
+    (verbatim . org-e-html-verbatim)
+    (verse-block . org-e-html-verse-block))
+  "Alist between element or object types and translators.")
 
 (defconst org-e-html-option-alist
   '((:agenda-style nil nil org-agenda-export-html-style)
@@ -109,31 +163,18 @@
     (:xml-declaration nil nil org-e-html-xml-declaration)
     (:LaTeX-fragments nil "LaTeX" org-export-with-LaTeX-fragments)
     (:mathjax "MATHJAX" nil "" space))
-  "Alist between export properties and ways to set them.
-
-The car of the alist is the property name, and the cdr is a list
-like \(KEYWORD OPTION DEFAULT BEHAVIOUR\) where:
-
-KEYWORD is a string representing a buffer keyword, or nil.
-OPTION is a string that could be found in an #+OPTIONS: line.
-DEFAULT is the default value for the property.
-BEHAVIOUR determine how Org should handle multiple keywords for
-the same property.  It is a symbol among:
-  nil       Keep old value and discard the new one.
-  t         Replace old value with the new one.
-  `space'   Concatenate the values, separating them with a space.
-  `newline' Concatenate the values, separating them with
-            a newline.
-  `split'   Split values at white spaces, and cons them to the
-            previous list.
-
-KEYWORD and OPTION have precedence over DEFAULT.
-
-All these properties should be back-end agnostic.  For back-end
-specific properties, define a similar variable named
-`org-BACKEND-option-alist', replacing BACKEND with the name of
-the appropriate back-end.  You can also redefine properties
-there, as they have precedence over these.")
+  "Alist between HTML export properties and ways to set them.
+See `org-export-option-alist' for more information on the
+structure of the values.")
+
+(defconst org-e-html-filters-alist
+  '((:filter-final-output . org-e-html-final-function))
+  "Alist between filters keywords and back-end specific filters.
+See `org-export-filters-alist' for more information.")
+
+
+
+;;; Internal Variables
 
 ;; FIXME: it already exists in org-e-html.el
 (defconst org-e-html-cvt-link-fn
@@ -3023,16 +3064,6 @@ contextual information."
 
 ;;; Filter Functions
 
-;;;; Filter Settings
-
-(defconst org-e-html-filters-alist
-  '((:filter-final-output . org-e-html-final-function))
-  "Alist between filters keywords and back-end specific filters.
-See `org-export-filters-alist' for more information.")
-
-
-;;;; Filters
-
 (defun org-e-html-final-function (contents backend info)
   (if (not org-e-html-pretty-output) contents
     (with-temp-buffer

+ 58 - 2
contrib/lisp/org-e-latex.el

@@ -81,7 +81,63 @@
 
 
 
-;;; Internal Variables
+;;; Define Back-End
+
+(defvar org-e-latex-translate-alist
+  '((babel-call . org-e-latex-babel-call)
+    (bold . org-e-latex-bold)
+    (center-block . org-e-latex-center-block)
+    (clock . org-e-latex-clock)
+    (code . org-e-latex-code)
+    (comment . org-e-latex-comment)
+    (comment-block . org-e-latex-comment-block)
+    (drawer . org-e-latex-drawer)
+    (dynamic-block . org-e-latex-dynamic-block)
+    (entity . org-e-latex-entity)
+    (example-block . org-e-latex-example-block)
+    (export-block . org-e-latex-export-block)
+    (export-snippet . org-e-latex-export-snippet)
+    (fixed-width . org-e-latex-fixed-width)
+    (footnote-definition . org-e-latex-footnote-definition)
+    (footnote-reference . org-e-latex-footnote-reference)
+    (headline . org-e-latex-headline)
+    (horizontal-rule . org-e-latex-horizontal-rule)
+    (inline-babel-call . org-e-latex-inline-babel-call)
+    (inline-src-block . org-e-latex-inline-src-block)
+    (inlinetask . org-e-latex-inlinetask)
+    (italic . org-e-latex-italic)
+    (item . org-e-latex-item)
+    (keyword . org-e-latex-keyword)
+    (latex-environment . org-e-latex-latex-environment)
+    (latex-fragment . org-e-latex-latex-fragment)
+    (line-break . org-e-latex-line-break)
+    (link . org-e-latex-link)
+    (macro . org-e-latex-macro)
+    (paragraph . org-e-latex-paragraph)
+    (plain-list . org-e-latex-plain-list)
+    (plain-text . org-e-latex-plain-text)
+    (planning . org-e-latex-planning)
+    (property-drawer . org-e-latex-property-drawer)
+    (quote-block . org-e-latex-quote-block)
+    (quote-section . org-e-latex-quote-section)
+    (radio-target . org-e-latex-radio-target)
+    (section . org-e-latex-section)
+    (special-block . org-e-latex-special-block)
+    (src-block . org-e-latex-src-block)
+    (statistics-cookie . org-e-latex-statistics-cookie)
+    (strike-through . org-e-latex-strike-through)
+    (subscript . org-e-latex-subscript)
+    (superscript . org-e-latex-superscript)
+    (table . org-e-latex-table)
+    (table-cell . org-e-latex-table-cell)
+    (table-row . org-e-latex-table-row)
+    (target . org-e-latex-target)
+    (template . org-e-latex-template)
+    (timestamp . org-e-latex-timestamp)
+    (underline . org-e-latex-underline)
+    (verbatim . org-e-latex-verbatim)
+    (verse-block . org-e-latex-verse-block))
+  "Alist between element or object types and translators.")
 
 (defconst org-e-latex-option-alist
   '((:date "DATE" nil org-e-latex-date-format t)
@@ -90,7 +146,7 @@
     (:latex-header-extra "LATEX_HEADER" nil nil newline))
   "Alist between LaTeX export properties and ways to set them.
 See `org-export-option-alist' for more information on the
-structure of the value.")
+structure of the values.")
 
 
 

+ 86 - 47
contrib/lisp/org-e-odt.el

@@ -24,9 +24,95 @@
 ;;; Commentary:
 
 ;;; Code:
+
 (eval-when-compile
   (require 'cl))
 
+
+;;; Define Back-End
+
+(defvar org-e-odt-translate-alist
+  '((babel-call . org-e-odt-babel-call)
+    (bold . org-e-odt-bold)
+    (center-block . org-e-odt-center-block)
+    (clock . org-e-odt-clock)
+    (code . org-e-odt-code)
+    (comment . org-e-odt-comment)
+    (comment-block . org-e-odt-comment-block)
+    (drawer . org-e-odt-drawer)
+    (dynamic-block . org-e-odt-dynamic-block)
+    (entity . org-e-odt-entity)
+    (example-block . org-e-odt-example-block)
+    (export-block . org-e-odt-export-block)
+    (export-snippet . org-e-odt-export-snippet)
+    (fixed-width . org-e-odt-fixed-width)
+    (footnote-definition . org-e-odt-footnote-definition)
+    (footnote-reference . org-e-odt-footnote-reference)
+    (headline . org-e-odt-headline)
+    (horizontal-rule . org-e-odt-horizontal-rule)
+    (inline-babel-call . org-e-odt-inline-babel-call)
+    (inline-src-block . org-e-odt-inline-src-block)
+    (inlinetask . org-e-odt-inlinetask)
+    (italic . org-e-odt-italic)
+    (item . org-e-odt-item)
+    (keyword . org-e-odt-keyword)
+    (latex-environment . org-e-odt-latex-environment)
+    (latex-fragment . org-e-odt-latex-fragment)
+    (line-break . org-e-odt-line-break)
+    (link . org-e-odt-link)
+    (macro . org-e-odt-macro)
+    (paragraph . org-e-odt-paragraph)
+    (plain-list . org-e-odt-plain-list)
+    (plain-text . org-e-odt-plain-text)
+    (planning . org-e-odt-planning)
+    (property-drawer . org-e-odt-property-drawer)
+    (quote-block . org-e-odt-quote-block)
+    (quote-section . org-e-odt-quote-section)
+    (radio-target . org-e-odt-radio-target)
+    (section . org-e-odt-section)
+    (special-block . org-e-odt-special-block)
+    (src-block . org-e-odt-src-block)
+    (statistics-cookie . org-e-odt-statistics-cookie)
+    (strike-through . org-e-odt-strike-through)
+    (subscript . org-e-odt-subscript)
+    (superscript . org-e-odt-superscript)
+    (table . org-e-odt-table)
+    (table-cell . org-e-odt-table-cell)
+    (table-row . org-e-odt-table-row)
+    (target . org-e-odt-target)
+    (template . org-e-odt-template)
+    (timestamp . org-e-odt-timestamp)
+    (underline . org-e-odt-underline)
+    (verbatim . org-e-odt-verbatim)
+    (verse-block . org-e-odt-verse-block))
+  "Alist between element or object types and translators.")
+
+(defvar org-e-odt-option-alist
+  '(
+    ;; (:agenda-style nil nil org-agenda-export-html-style)
+    ;; (:convert-org-links nil nil org-e-odt-link-org-files-as-html)
+    ;; ;; FIXME Use (org-xml-encode-org-text-skip-links s) ??
+    ;; ;; (:expand-quoted-html nil "@" org-e-odt-expand)
+    ;; (:inline-images nil nil org-e-odt-inline-images)
+    ;; ;; (:link-home nil nil org-e-odt-link-home) FIXME
+    ;; ;; (:link-up nil nil org-e-odt-link-up) FIXME
+    ;; (:style nil nil org-e-odt-style)
+    ;; (:style-extra nil nil org-e-odt-style-extra)
+    ;; (:style-include-default nil nil org-e-odt-style-include-default)
+    ;; (:style-include-scripts nil nil org-e-odt-style-include-scripts)
+    ;; ;; (:timestamp nil nil org-e-odt-with-timestamp)
+    ;; (:html-extension nil nil org-e-odt-extension)
+    ;; (:html-postamble nil nil org-e-odt-postamble)
+    ;; (:html-preamble nil nil org-e-odt-preamble)
+    ;; (:html-table-tag nil nil org-e-odt-table-tag)
+    ;; (:xml-declaration nil nil org-e-odt-xml-declaration)
+    (:odt-styles-file "ODT_STYLES_FILE" nil nil t)
+    (:LaTeX-fragments nil "LaTeX" org-export-with-LaTeX-fragments))
+  "Alist between ODT export properties and ways to set them.
+See `org-export-option-alist' for more information on the
+structure of the values.")
+
+
 ;; FIXMES
 ;; org-e-odt-preprocess-latex-fragments
 ;; org-export-as-e-odt-and-open
@@ -1762,53 +1848,6 @@ captions on export.")
 
 ;;;; HTML Internal Variables
 
-(defvar org-e-odt-option-alist
-  '(
-    ;; (:agenda-style nil nil org-agenda-export-html-style)
-    ;; (:convert-org-links nil nil org-e-odt-link-org-files-as-html)
-    ;; ;; FIXME Use (org-xml-encode-org-text-skip-links s) ??
-    ;; ;; (:expand-quoted-html nil "@" org-e-odt-expand)
-    ;; (:inline-images nil nil org-e-odt-inline-images)
-    ;; ;; (:link-home nil nil org-e-odt-link-home) FIXME
-    ;; ;; (:link-up nil nil org-e-odt-link-up) FIXME
-    ;; (:style nil nil org-e-odt-style)
-    ;; (:style-extra nil nil org-e-odt-style-extra)
-    ;; (:style-include-default nil nil org-e-odt-style-include-default)
-    ;; (:style-include-scripts nil nil org-e-odt-style-include-scripts)
-    ;; ;; (:timestamp nil nil org-e-odt-with-timestamp)
-    ;; (:html-extension nil nil org-e-odt-extension)
-    ;; (:html-postamble nil nil org-e-odt-postamble)
-    ;; (:html-preamble nil nil org-e-odt-preamble)
-    ;; (:html-table-tag nil nil org-e-odt-table-tag)
-    ;; (:xml-declaration nil nil org-e-odt-xml-declaration)
-    (:odt-styles-file "ODT_STYLES_FILE" nil nil t)
-    (:LaTeX-fragments nil "LaTeX" org-export-with-LaTeX-fragments))
-  "Alist between export properties and ways to set them.
-
-The car of the alist is the property name, and the cdr is a list
-like \(KEYWORD OPTION DEFAULT BEHAVIOUR\) where:
-
-KEYWORD is a string representing a buffer keyword, or nil.
-OPTION is a string that could be found in an #+OPTIONS: line.
-DEFAULT is the default value for the property.
-BEHAVIOUR determine how Org should handle multiple keywords for
-the same property.  It is a symbol among:
-  nil       Keep old value and discard the new one.
-  t         Replace old value with the new one.
-  `space'   Concatenate the values, separating them with a space.
-  `newline' Concatenate the values, separating them with
-            a newline.
-  `split'   Split values at white spaces, and cons them to the
-            previous list.
-
-KEYWORD and OPTION have precedence over DEFAULT.
-
-All these properties should be back-end agnostic.  For back-end
-specific properties, define a similar variable named
-`org-BACKEND-option-alist', replacing BACKEND with the name of
-the appropriate back-end.  You can also redefine properties
-there, as they have precedence over these.")
-
 (defvar html-table-tag nil) ; dynamically scoped into this.
 
 ;; FIXME: it already exists in org-e-odt.el

+ 55 - 39
contrib/lisp/org-export.el

@@ -46,50 +46,60 @@
 ;; The core function is `org-export-as'.  It returns the transcoded
 ;; buffer as a string.
 ;;
-;; In order to derive an exporter out of this generic implementation,
-;; one can define a transcode function for each element or object.
-;; Such function should return a string for the corresponding element,
-;; without any trailing space, or nil.  It must accept three
-;; arguments:
-;; 1. the element or object itself,
-;; 2. its contents, or nil when it isn't recursive,
-;; 3. the property list used as a communication channel.
-;;
-;; If no such function is found, that element or object type will
-;; simply be ignored, along with any separating blank line.  The same
-;; will happen if the function returns the nil value.  If that
-;; function returns the empty string, the type will be ignored, but
-;; the blank lines will be kept.
-;;
-;; Contents, when not nil, are stripped from any global indentation
-;; (although the relative one is preserved).  They also always end
-;; with a single newline character.
-;;
-;; These functions must follow a strict naming convention:
-;; `org-BACKEND-TYPE' where, obviously, BACKEND is the name of the
-;; export back-end and TYPE the type of the element or object handled.
-;;
-;; Moreover, two additional functions can be defined.  On the one
-;; hand, `org-BACKEND-template' returns the final transcoded string,
-;; and can be used to add a preamble and a postamble to document's
-;; body.  It must accept two arguments: the transcoded string and the
-;; property list containing export options.  On the other hand,
-;; `org-BACKEND-plain-text', when defined, is to be called on every
-;; text not recognized as an element or an object.  It must accept two
-;; arguments: the text string and the information channel.
+;; In order to implement a back-end for this generic exporter, up to
+;; three steps may be needed:
+;;
+;; 1. Define a variable, `org-BACKEND-translate-alist' where elements
+;;    and objects types are associated to translator functions.
+;;
+;;    These functions should return a string without any trailing
+;;    space, or nil.  They must accept three arguments: the object or
+;;    element itself, its contents or nil when it isn't recursive and
+;;    the property list used as a communication channel.
+;;
+;;    Contents, when not nil, are stripped from any global indentation
+;;    (although the relative one is preserved).  They also always end
+;;    with a single newline character.
+;;
+;;    If, for a given type, no function is found, that element or
+;;    object type will simply be ignored, along with any blank line or
+;;    white space at its end.  The same will happen if the function
+;;    returns the nil value.  If that function returns the empty
+;;    string, the type will be ignored, but the blank lines or white
+;;    spaces will be kept.
+;;
+;;    In addition to element and object types, one function can be
+;;    associated to the `template' symbol and another one to the
+;;    `plain-list' symbol.  The former returns the final transcoded
+;;    string, and can be used to add a preamble and a postamble to
+;;    document's body.  It must accept two arguments: the transcoded
+;;    string and the property list containing export options.  The
+;;    latter, when defined, is to be called on every text not
+;;    recognized as an element or an object.  It must accept two
+;;    arguments: the text string and the information channel.
+;;
+;; 2. Optionally define a variable, `org-BACKEND-option-alist', in
+;;    order to support new export options, buffer keywords or
+;;    "#+OPTIONS:" items specific to the back-end.  See
+;;    `org-export-option-alist' for supported defaults and syntax.
+;;
+;; 3. Optionally define a variable, `org-BACKEND-filters-alist', in
+;;    order to apply developer filters.  See "The Filter System"
+;;    section in this file for more information.
+;;
+;; If the new back-end shares most properties with another one,
+;; `org-export-define-derived-backend' can be used to simplify the
+;; process.
 ;;
 ;; Any back-end can define its own variables.  Among them, those
 ;; customizables should belong to the `org-export-BACKEND' group.
-;; Also, a special variable, `org-BACKEND-option-alist', allows to
-;; define buffer keywords and "#+options:" items specific to that
-;; back-end.  See `org-export-option-alist' for supported defaults and
-;; syntax.
 ;;
 ;; Tools for common tasks across back-ends are implemented in the
 ;; penultimate part of this file.  A dispatcher for standard back-ends
 ;; is provided in the last one.
 
 ;;; Code:
+
 (eval-when-compile (require 'cl))
 (require 'org-element)
 ;; Require major back-ends and publishing tools
@@ -1542,7 +1552,10 @@ non-nil, is a list of tags marking a subtree as exportable."
 ;; parse tree traversals skip it, `org-export-interpret-p' tells which
 ;; elements or objects should be seen as real Org syntax and
 ;; `org-export-expand' transforms the others back into their original
-;; shape.
+;; shape
+;;
+;; `org-export-transcoder' is an accessor returning appropriate
+;; translator function for a given element or object.
 
 (defun org-export-transcoder (blob info)
   "Return appropriate transcoder for BLOB.
@@ -1550,9 +1563,12 @@ INFO is a plist containing export directives."
   (let ((type (org-element-type blob)))
     ;; Return contents only for complete parse trees.
     (if (eq type 'org-data) (lambda (blob contents info) contents)
-      (let ((transcoder
-             (intern (format "org-%s-%s" (plist-get info :back-end) type))))
-        (and (fboundp transcoder) transcoder)))))
+      (let ((translate-alist
+	     (intern (format "org-%s-translate-alist"
+			     (plist-get info :back-end)))))
+	(when (boundp translate-alist)
+	  (let ((transcoder (cdr (assq type (symbol-value translate-alist)))))
+	    (and (fboundp transcoder) transcoder)))))))
 
 (defun org-export-data (data info)
   "Convert DATA into current back-end format.

+ 61 - 60
testing/lisp/test-org-export.el

@@ -23,20 +23,27 @@
 (defmacro org-test-with-backend (backend &rest body)
   "Execute body with an export back-end defined.
 
-BACKEND is the name, as a string, of the back-end.  BODY is the
-body to execute.  The defined back-end simply returns parsed data
-as Org syntax."
+BACKEND is the name of the back-end.  BODY is the body to
+execute.  The defined back-end simply returns parsed data as Org
+syntax."
   (declare (debug (form body)) (indent 1))
-  `(flet ,(let (transcoders)
-	    (dolist (type (append org-element-all-elements
-				  org-element-all-objects)
-			  transcoders)
-	      (push `(,(intern (format "org-%s-%s" backend type))
-		      (obj contents info)
-		      (,(intern (format "org-element-%s-interpreter" type))
-		       obj contents))
-		    transcoders)))
-     ,@body))
+  `(let ((,(intern (format "org-%s-translate-alist" backend))
+	  ',(let (transcode-table)
+	      (dolist (type (append org-element-all-elements
+				    org-element-all-objects)
+			    transcode-table)
+		(push (cons type (intern (format "org-%s-%s" backend type)))
+		      transcode-table)))))
+     (flet ,(let (transcoders)
+	      (dolist (type (append org-element-all-elements
+				    org-element-all-objects)
+			    transcoders)
+		(push `(,(intern (format "org-%s-%s" backend type))
+			(obj contents info)
+			(,(intern (format "org-element-%s-interpreter" type))
+			 obj contents))
+		      transcoders)))
+       ,@body)))
 
 (defmacro org-test-with-parsed-data (data &rest body)
   "Execute body with parsed data available.
@@ -140,7 +147,7 @@ already filled in `info'."
   "Test if export options have an impact on output."
   ;; Test exclude tags.
   (org-test-with-temp-text "* Head1 :noexport:"
-    (org-test-with-backend "test"
+    (org-test-with-backend test
       (should
        (equal (org-export-as 'test nil nil nil '(:exclude-tags ("noexport")))
 	      ""))))
@@ -150,7 +157,7 @@ already filled in `info'."
 ** Sub-Head1.1 :export:
 *** Sub-Head1.1.1
 * Head2"
-    (org-test-with-backend "test"
+    (org-test-with-backend test
       (should
        (string-match
 	"\\* Head1\n\\*\\* Sub-Head1.1[ \t]+:export:\n\\*\\*\\* Sub-Head1.1.1\n"
@@ -162,7 +169,7 @@ already filled in `info'."
 ** Sub-Head2
 * Head2 :noexport:
 ** Sub-Head1 :export:"
-    (org-test-with-backend "test"
+    (org-test-with-backend test
       (should
        (string-match
 	"\\* Head1[ \t]+:export:\n\\*\\* Sub-Head2\n"
@@ -172,24 +179,24 @@ already filled in `info'."
   ;; Ignore tasks.
   (let ((org-todo-keywords '((sequence "TODO" "DONE"))))
     (org-test-with-temp-text "* TODO Head1"
-      (org-test-with-backend "test"
+      (org-test-with-backend test
 	(should (equal (org-export-as 'test nil nil nil '(:with-tasks nil))
 		       "")))))
   (let ((org-todo-keywords '((sequence "TODO" "DONE"))))
     (org-test-with-temp-text "* TODO Head1"
-      (org-test-with-backend "test"
+      (org-test-with-backend test
 	(should (equal (org-export-as 'test nil nil nil '(:with-tasks t))
 		       "* TODO Head1\n")))))
   ;; Archived tree.
   (org-test-with-temp-text "* Head1 :archive:"
     (let ((org-archive-tag "archive"))
-      (org-test-with-backend "test"
+      (org-test-with-backend test
 	(should
 	 (equal (org-export-as 'test nil nil nil '(:with-archived-trees nil))
 		"")))))
   (org-test-with-temp-text "* Head1 :archive:\nbody\n** Sub-head 2"
     (let ((org-archive-tag "archive"))
-      (org-test-with-backend "test"
+      (org-test-with-backend test
 	(should
 	 (string-match
 	  "\\* Head1[ \t]+:archive:"
@@ -197,7 +204,7 @@ already filled in `info'."
 			 '(:with-archived-trees headline)))))))
   (org-test-with-temp-text "* Head1 :archive:"
     (let ((org-archive-tag "archive"))
-      (org-test-with-backend "test"
+      (org-test-with-backend test
 	(should
 	 (string-match
 	  "\\`\\* Head1[ \t]+:archive:\n\\'"
@@ -205,20 +212,20 @@ already filled in `info'."
   ;; Drawers.
   (let ((org-drawers '("TEST")))
     (org-test-with-temp-text ":TEST:\ncontents\n:END:"
-      (org-test-with-backend "test"
+      (org-test-with-backend test
 	(should (equal (org-export-as 'test nil nil nil '(:with-drawers nil))
 		       ""))
 	(should (equal (org-export-as 'test nil nil nil '(:with-drawers t))
 		       ":TEST:\ncontents\n:END:\n")))))
   (let ((org-drawers '("FOO" "BAR")))
     (org-test-with-temp-text ":FOO:\nkeep\n:END:\n:BAR:\nremove\n:END:"
-      (org-test-with-backend "test"
+      (org-test-with-backend test
 	(should
 	 (equal (org-export-as 'test nil nil nil '(:with-drawers ("FOO")))
 		":FOO:\nkeep\n:END:\n")))))
   ;; Timestamps.
   (org-test-with-temp-text "[2012-04-29 sun. 10:45]<2012-04-29 sun. 10:45>"
-    (org-test-with-backend "test"
+    (org-test-with-backend test
       (should
        (equal (org-export-as 'test nil nil nil '(:with-timestamps t))
 	      "[2012-04-29 sun. 10:45]<2012-04-29 sun. 10:45>\n"))
@@ -233,7 +240,7 @@ already filled in `info'."
   ;; Clocks.
   (let ((org-clock-string "CLOCK:"))
     (org-test-with-temp-text "CLOCK: [2012-04-29 sun. 10:45]"
-      (org-test-with-backend "test"
+      (org-test-with-backend test
 	(should
 	 (equal (org-export-as 'test nil nil nil '(:with-clocks t))
 		"CLOCK: [2012-04-29 sun. 10:45]\n"))
@@ -242,7 +249,7 @@ already filled in `info'."
   ;; Plannings.
   (let ((org-closed-string "CLOSED:"))
     (org-test-with-temp-text "CLOSED: [2012-04-29 sun. 10:45]"
-      (org-test-with-backend "test"
+      (org-test-with-backend test
 	(should
 	 (equal (org-export-as 'test nil nil nil '(:with-plannings t))
 		"CLOSED: [2012-04-29 sun. 10:45]\n"))
@@ -254,7 +261,7 @@ already filled in `info'."
   "Test if export process ignores commented trees."
   (let ((org-comment-string "COMMENT"))
     (org-test-with-temp-text "* COMMENT Head1"
-      (org-test-with-backend "test"
+      (org-test-with-backend test
 	(should (equal (org-export-as 'test) ""))))))
 
 (ert-deftest test-org-export/export-scope ()
@@ -264,7 +271,7 @@ already filled in `info'."
 ** Head2
 text
 *** Head3"
-    (org-test-with-backend "test"
+    (org-test-with-backend test
       ;; Subtree.
       (forward-line 3)
       (should (equal (org-export-as 'test 'subtree) "text\n*** Head3\n"))
@@ -297,14 +304,14 @@ text
 #+BEGIN_SRC emacs-lisp
 \(+ 1 2)
 #+END_SRC"
-    (org-test-with-backend "test"
+    (org-test-with-backend test
       (forward-line 1)
       (should (equal (org-export-as 'test 'subtree) ": 3\n")))))
 
 (ert-deftest test-org-export/export-snippet ()
   "Test export snippets transcoding."
   (org-test-with-temp-text "<test@A><t@B>"
-    (org-test-with-backend "test"
+    (org-test-with-backend test
       (flet ((org-test-export-snippet
 	      (snippet contents info)
 	      (when (eq (org-export-snippet-backend snippet) 'test)
@@ -363,7 +370,7 @@ body\n")))
 
 (ert-deftest test-org-export/user-ignore-list ()
   "Test if `:ignore-list' accepts user input."
-  (org-test-with-backend "test"
+  (org-test-with-backend test
     (flet ((skip-note-head
 	    (data backend info)
 	    ;; Ignore headlines with the word "note" in their title.
@@ -382,7 +389,7 @@ body\n")))
 
 (ert-deftest test-org-export/before-parsing-hook ()
   "Test `org-export-before-parsing-hook'."
-  (org-test-with-backend "test"
+  (org-test-with-backend test
     (org-test-with-temp-text "* Headline 1\nBody 1\n* Headline 2\nBody 2"
       (let ((org-export-before-parsing-hook
 	     '((lambda ()
@@ -457,7 +464,7 @@ body\n")))
     (org-test-with-temp-text "[fn:1] Out of scope
 * Title
 Paragraph[fn:1]"
-      (org-test-with-backend "test"
+      (org-test-with-backend test
 	(flet ((org-test-footnote-reference
 		(fn-ref contents info)
 		(org-element-interpret-data
@@ -864,45 +871,39 @@ Another text. (ref:text)
 	  (mapcar (lambda (cell) (org-export-table-cell-alignment cell info))
 		  (org-element-map tree 'table-cell 'identity))))))
     ;; 2. The last alignment cookie has precedence.
-    (org-test-with-temp-text "
+    (org-test-with-parsed-data "
 | <l8> |
 | cell |
 | <r9> |"
-      (let* ((tree (org-element-parse-buffer))
-	     (info `(:parse-tree ,tree)))
-	(should
-	 (equal
-	  '(right right right)
-	  (mapcar (lambda (cell) (org-export-table-cell-alignment cell info))
-		  (org-element-map tree 'table-cell 'identity))))))
+      (should
+       (equal
+	'(right right right)
+	(mapcar (lambda (cell) (org-export-table-cell-alignment cell info))
+		(org-element-map tree 'table-cell 'identity)))))
     ;; 3. If there's no cookie, cell's contents determine alignment.
     ;;    A column mostly made of cells containing numbers will align
     ;;    its cells to the right.
-    (org-test-with-temp-text "
+    (org-test-with-parsed-data "
 | 123       |
 | some text |
 | 12345     |"
-      (let* ((tree (org-element-parse-buffer))
-	     (info `(:parse-tree ,tree)))
-	(should
-	 (equal
-	  '(right right right)
-	  (mapcar (lambda (cell)
-		    (org-export-table-cell-alignment cell info))
-		  (org-element-map tree 'table-cell 'identity))))))
-    ;; 5. Otherwise, they will be aligned to the left.
-    (org-test-with-temp-text "
+      (should
+       (equal
+	'(right right right)
+	(mapcar (lambda (cell)
+		  (org-export-table-cell-alignment cell info))
+		(org-element-map tree 'table-cell 'identity)))))
+    ;; 4. Otherwise, they will be aligned to the left.
+    (org-test-with-parsed-data "
 | text      |
 | some text |
 | \alpha    |"
-      (let* ((tree (org-element-parse-buffer))
-	     (info `(:parse-tree ,tree)))
-	(should
-	 (equal
-	  '(left left left)
-	  (mapcar (lambda (cell)
-		    (org-export-table-cell-alignment cell info))
-		  (org-element-map tree 'table-cell 'identity))))))))
+      (should
+       (equal
+	'(left left left)
+	(mapcar (lambda (cell)
+		  (org-export-table-cell-alignment cell info))
+		(org-element-map tree 'table-cell 'identity)))))))
 
 (ert-deftest test-org-export/table-cell-borders ()
   "Test `org-export-table-cell-borders' specifications."