ox: Change back-ends internal representation to structures

* lisp/ox.el (org-export--registered-backends): Renamed from
  `org-export-registered-backends'.
(org-export-invisible-backends): Removed variable.
(org-export-get-backend, org-export-get-all-transcoders
org-export-get-all-options, org-export-get-all-filters): New
functions.  It replaces `org-export-backend-translate-table'.
(org-export-barf-if-invalid-backend, org-export-derived-backend-p,
org-export-define-backend, org-export-define-derived-backend):
Rewrite functions using new representation.
(org-export-backend-translate-table): Remove function.
(org-export-get-environment): Use new function.
(org-export--get-subtree-options, org-export--parse-option-keyword,
org-export--get-inbuffer-options, org-export--get-global-options,
org-export-to-buffer org-export-to-file, org-export-string-as
org-export-replace-region-by): Update docstring.
(org-export-data-with-translations): Remove function.  Use
`org-export-data-with-backend' with a temporary back-end instead.
(org-export-data-with-backend, org-export-as): Reflect new definition
for back-ends.
(org-export--dispatch-action, org-export--dispatch-ui): Reflect new
definition for back-ends and variable removal.  Refactoring.
(org-export-filter-apply-functions): Call functions with
current back-end's name, not full back-end.
* lisp/org.el (org-export-backends, org-create-formula--latex-header):
Use new structure and variables.
* testing/lisp/test-ox.el: Update tests.

This patch separates back-end definition from its registration.  Thus,
it allows to use anonymous or unregistered back-ends.
This commit is contained in:
Nicolas Goaziou 2013-06-24 20:52:10 +02:00
parent 0e99027575
commit cea0434c4f
3 changed files with 764 additions and 602 deletions

View File

@ -436,8 +436,9 @@ For export specific modules, see also `org-export-backends'."
(const :tag "C wl: Links to Wanderlust folders/messages" org-wl)
(repeat :tag "External packages" :inline t (symbol :tag "Package"))))
(defvar org-export-registered-backends) ; From ox.el
(defvar org-export--registered-backends) ; From ox.el.
(declare-function org-export-derived-backend-p "ox" (backend &rest backends))
(declare-function org-export-backend-name "ox" (backend))
(defcustom org-export-backends '(ascii html icalendar latex)
"List of export back-ends that should be always available.
@ -451,30 +452,29 @@ needed.
This variable needs to be set before org.el is loaded. If you
need to make a change while Emacs is running, use the customize
interface or run the following code, where VALUE stands for the
new value of the variable, after updating it:
interface or run the following code, where VAL stands for the new
value of the variable, after updating it:
\(progn
\(setq org-export-registered-backends
\(setq org-export--registered-backends
\(org-remove-if-not
\(lambda (backend)
\(or (memq backend val)
\(catch 'parentp
\(mapc
\(lambda (b)
\(and (org-export-derived-backend-p b (car backend))
\(throw 'parentp t)))
val)
nil)))
org-export-registered-backends))
\(let ((new-list (mapcar 'car org-export-registered-backends)))
\(let ((name (org-export-backend-name backend)))
\(or (memq name val)
\(catch 'parentp
\(dolist (b val)
\(and (org-export-derived-backend-p b name)
\(throw 'parentp t)))))))
org-export--registered-backends))
\(let ((new-list (mapcar 'org-export-backend-name
org-export--registered-backends)))
\(dolist (backend val)
\(cond
\((not (load (format \"ox-%s\" backend) t t))
\(message \"Problems while trying to load export back-end `%s'\"
backend))
\((not (memq backend new-list)) (push backend new-list))))
\(set-default var new-list)))
\(set-default 'org-export-backends new-list)))
Adding a back-end to this list will also pull the back-end it
depends on, if any."
@ -488,21 +488,20 @@ depends on, if any."
;; Any back-end not required anymore (not present in VAL and not
;; a parent of any back-end in the new value) is removed from the
;; list of registered back-ends.
(setq org-export-registered-backends
(setq org-export--registered-backends
(org-remove-if-not
(lambda (backend)
(or (memq backend val)
(catch 'parentp
(mapc
(lambda (b)
(and (org-export-derived-backend-p b (car backend))
(throw 'parentp t)))
val)
nil)))
org-export-registered-backends))
(let ((name (org-export-backend-name backend)))
(or (memq name val)
(catch 'parentp
(dolist (b val)
(and (org-export-derived-backend-p b name)
(throw 'parentp t)))))))
org-export--registered-backends))
;; Now build NEW-LIST of both new back-ends and required
;; parents.
(let ((new-list (mapcar 'car org-export-registered-backends)))
(let ((new-list (mapcar 'org-export-backend-name
org-export--registered-backends)))
(dolist (backend val)
(cond
((not (load (format "ox-%s" backend) t t))
@ -18494,14 +18493,17 @@ share a good deal of logic."
"Invalid value of `org-latex-create-formula-image-program'")))
string tofile options buffer))
(declare-function org-export-get-backend "ox" (name))
(declare-function org-export--get-global-options "ox" (&optional backend))
(declare-function org-export--get-inbuffer-options "ox" (&optional backend))
(declare-function org-latex-guess-inputenc "ox-latex" (header))
(declare-function org-latex-guess-babel-language "ox-latex" (header info))
(defun org-create-formula--latex-header ()
"Return LaTeX header appropriate for previewing a LaTeX snippet."
(let ((info (org-combine-plists (org-export--get-global-options 'latex)
(org-export--get-inbuffer-options 'latex))))
(let ((info (org-combine-plists (org-export--get-global-options
(org-export-get-backend 'latex))
(org-export--get-inbuffer-options
(org-export-get-backend 'latex)))))
(org-latex-guess-babel-language
(org-latex-guess-inputenc
(org-splice-latex-header

View File

@ -47,15 +47,10 @@
;; The core function is `org-export-as'. It returns the transcoded
;; buffer as a string.
;;
;; An export back-end is defined with `org-export-define-backend',
;; which defines one mandatory information: his translation table.
;; Its value is an alist whose keys are elements and objects types and
;; values translator functions. See function's docstring for more
;; information about translators.
;;
;; Optionally, `org-export-define-backend' can also support specific
;; buffer keywords, OPTION keyword's items and filters. Also refer to
;; function documentation for more information.
;; An export back-end is defined with `org-export-define-backend'.
;; This function can also support specific buffer keywords, OPTION
;; keyword's items and filters. Refer to function's documentation 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
@ -280,14 +275,8 @@ containing the back-end used, as a symbol, and either a process
or the time at which it finished. It is used to build the menu
from `org-export-stack'.")
(defvar org-export-registered-backends nil
(defvar org-export--registered-backends nil
"List of backends currently available in the exporter.
A backend is stored as a list where CAR is its name, as a symbol,
and CDR is a plist with the following properties:
`:filters-alist', `:menu-entry', `:options-alist' and
`:translate-alist'.
This variable is set with `org-export-define-backend' and
`org-export-define-derived-backend' functions.")
@ -830,20 +819,6 @@ process faster and the export more portable."
:package-version '(Org . "8.0")
:type '(file :must-match t))
(defcustom org-export-invisible-backends nil
"List of back-ends that shouldn't appear in the dispatcher.
Any back-end belonging to this list or derived from a back-end
belonging to it will not appear in the dispatcher menu.
Indeed, Org may require some export back-ends without notice. If
these modules are never to be used interactively, adding them
here will avoid cluttering the dispatcher menu."
:group 'org-export-general
:version "24.4"
:package-version '(Org . "8.0")
:type '(repeat (symbol :tag "Back-End")))
(defcustom org-export-dispatch-use-expert-ui nil
"Non-nil means using a non-intrusive `org-export-dispatch'.
In that case, no help buffer is displayed. Though, an indicator
@ -863,25 +838,147 @@ mode."
;;; Defining Back-ends
;;
;; `org-export-define-backend' is the standard way to define an export
;; back-end. It allows to specify translators, filters, buffer
;; options and a menu entry. If the new back-end shares translators
;; with another back-end, `org-export-define-derived-backend' may be
;; used instead.
;; An export back-end is a structure with `org-export-backend' type
;; and `name', `parent', `transcoders', `options', `filters', `blocks'
;; and `menu' slots.
;;
;; Internally, a back-end is stored as a list, of which CAR is the
;; name of the back-end, as a symbol, and CDR a plist. Accessors to
;; properties of a given back-end are: `org-export-backend-filters',
;; `org-export-backend-menu', `org-export-backend-options' and
;; `org-export-backend-translate-table'.
;; At the lowest level, a back-end is created with
;; `org-export-create-backend' function.
;;
;; A named back-end can be registered with
;; `org-export-register-backend' function. A registered back-end can
;; later be referred to by its name, with `org-export-get-backend'
;; function. Also, such a back-end can become the parent of a derived
;; back-end from which slot values will be inherited by default.
;; `org-export-derived-backend-p' can check if a given back-end is
;; derived from a list of back-end names.
;;
;; `org-export-get-all-transcoders', `org-export-get-all-options' and
;; `org-export-get-all-filters' return the full alist of transcoders,
;; options and filters, including those inherited from ancestors.
;;
;; At a higher level, `org-export-define-backend' is the standard way
;; to define an export back-end. If the new back-end is similar to
;; a registered back-end, `org-export-define-derived-backend' may be
;; used instead.
;;
;; Eventually `org-export-barf-if-invalid-backend' returns an error
;; when a given back-end hasn't been registered yet.
(defun org-export-define-backend (backend translators &rest body)
(defstruct (org-export-backend (:constructor org-export-create-backend)
(:copier nil))
name parent transcoders options filters blocks menu)
(defun org-export-get-backend (name)
"Return export back-end named after NAME.
NAME is a symbol. Return nil if no such back-end is found."
(catch 'found
(dolist (b org-export--registered-backends)
(when (eq (org-export-backend-name b) name)
(throw 'found b)))))
(defun org-export-register-backend (backend)
"Register BACKEND as a known export back-end.
BACKEND is a structure with `org-export-backend' type."
;; Refuse to register an unnamed back-end.
(unless (org-export-backend-name backend)
(error "Cannot register a unnamed export back-end"))
;; Refuse to register a back-end with an unknown parent.
(let ((parent (org-export-backend-parent backend)))
(when (and parent (not (org-export-get-backend parent)))
(error "Cannot use unknown \"%s\" back-end as a parent" parent)))
;; Register dedicated export blocks in the parser.
(dolist (name (org-export-backend-blocks backend))
(add-to-list 'org-element-block-name-alist
(cons name 'org-element-export-block-parser)))
;; If a back-end with the same name as BACKEND is already
;; registered, replace it with BACKEND. Otherwise, simply add
;; BACKEND to the list of registered back-ends.
(let ((old (org-export-get-backend (org-export-backend-name backend))))
(if old (setcar (memq old org-export--registered-backends) backend)
(push backend org-export--registered-backends))))
(defun org-export-barf-if-invalid-backend (backend)
"Signal an error if BACKEND isn't defined."
(unless (org-export-backend-p backend)
(error "Unknown \"%s\" back-end: Aborting export" backend)))
(defun org-export-derived-backend-p (backend &rest backends)
"Non-nil if BACKEND is derived from one of BACKENDS.
BACKEND is an export back-end, as returned by, e.g.,
`org-export-create-backend', or a symbol referring to
a registered back-end. BACKENDS is constituted of symbols."
(when (symbolp backend) (setq backend (org-export-get-backend backend)))
(when backend
(catch 'exit
(while (org-export-backend-parent backend)
(when (memq (org-export-backend-name backend) backends)
(throw 'exit t))
(setq backend
(org-export-get-backend (org-export-backend-parent backend))))
(memq (org-export-backend-name backend) backends))))
(defun org-export-get-all-transcoders (backend)
"Return full translation table for BACKEND.
BACKEND is an export back-end, as return by, e.g,,
`org-export-create-backend'. Return value is an alist where
keys are element or object types, as symbols, and values are
transcoders.
Unlike to `org-export-backend-transcoders', this function
also returns transcoders inherited from parent back-ends,
if any."
(when (symbolp backend) (setq backend (org-export-get-backend backend)))
(when backend
(let ((transcoders (org-export-backend-transcoders backend))
parent)
(while (setq parent (org-export-backend-parent backend))
(setq backend (org-export-get-backend parent))
(setq transcoders
(append transcoders (org-export-backend-transcoders backend))))
transcoders)))
(defun org-export-get-all-options (backend)
"Return export options for BACKEND.
BACKEND is an export back-end, as return by, e.g,,
`org-export-create-backend'. See `org-export-options-alist'
for the shape of the return value.
Unlike to `org-export-backend-options', this function also
returns options inherited from parent back-ends, if any."
(when (symbolp backend) (setq backend (org-export-get-backend backend)))
(when backend
(let ((options (org-export-backend-options backend))
parent)
(while (setq parent (org-export-backend-parent backend))
(setq backend (org-export-get-backend parent))
(setq options (append options (org-export-backend-options backend))))
options)))
(defun org-export-get-all-filters (backend)
"Return complete list of filters for BACKEND.
BACKEND is an export back-end, as return by, e.g,,
`org-export-create-backend'. Return value is an alist where
keys are symbols and values lists of functions.
Unlike to `org-export-backend-filters', this function also
returns filters inherited from parent back-ends, if any."
(when (symbolp backend) (setq backend (org-export-get-backend backend)))
(when backend
(let ((filters (org-export-backend-filters backend))
parent)
(while (setq parent (org-export-backend-parent backend))
(setq backend (org-export-get-backend parent))
(setq filters (append filters (org-export-backend-filters backend))))
filters)))
(defun org-export-define-backend (backend transcoders &rest body)
"Define a new back-end BACKEND.
TRANSLATORS is an alist between object or element types and
TRANSCODERS is an alist between object or element types and
functions handling them.
These functions should return a string without any trailing
@ -997,32 +1094,23 @@ keywords are understood:
`org-export-options-alist' for more information about
structure of the values."
(declare (indent 1))
(let (export-block filters menu-entry options contents)
(let (blocks filters menu-entry options contents)
(while (keywordp (car body))
(case (pop body)
(:export-block (let ((names (pop body)))
(setq export-block
(if (consp names) (mapcar 'upcase names)
(list (upcase names))))))
(setq blocks (if (consp names) (mapcar 'upcase names)
(list (upcase names))))))
(:filters-alist (setq filters (pop body)))
(:menu-entry (setq menu-entry (pop body)))
(:options-alist (setq options (pop body)))
(t (pop body))))
(setq contents (append (list :translate-alist translators)
(and filters (list :filters-alist filters))
(and options (list :options-alist options))
(and menu-entry (list :menu-entry menu-entry))))
;; Register back-end.
(let ((registeredp (assq backend org-export-registered-backends)))
(if registeredp (setcdr registeredp contents)
(push (cons backend contents) org-export-registered-backends)))
;; Tell parser to not parse EXPORT-BLOCK blocks.
(when export-block
(mapc
(lambda (name)
(add-to-list 'org-element-block-name-alist
`(,name . org-element-export-block-parser)))
export-block))))
(org-export-register-backend
(org-export-create-backend :name backend
:transcoders transcoders
:options options
:filters filters
:blocks blocks
:menu menu-entry))))
(defun org-export-define-derived-backend (child parent &rest body)
"Create a new back-end as a variant of an existing one.
@ -1077,75 +1165,25 @@ The back-end could then be called with, for example:
\(org-export-to-buffer 'my-latex \"*Test my-latex*\")"
(declare (indent 2))
(let (export-block filters menu-entry options translators contents)
(let (blocks filters menu-entry options transcoders contents)
(while (keywordp (car body))
(case (pop body)
(:export-block (let ((names (pop body)))
(setq export-block
(if (consp names) (mapcar 'upcase names)
(list (upcase names))))))
(setq blocks (if (consp names) (mapcar 'upcase names)
(list (upcase names))))))
(:filters-alist (setq filters (pop body)))
(:menu-entry (setq menu-entry (pop body)))
(:options-alist (setq options (pop body)))
(:translate-alist (setq translators (pop body)))
(:translate-alist (setq transcoders (pop body)))
(t (pop body))))
(setq contents (append
(list :parent parent)
(let ((p-table (org-export-backend-translate-table parent)))
(list :translate-alist (append translators p-table)))
(let ((p-filters (org-export-backend-filters parent)))
(list :filters-alist (append filters p-filters)))
(let ((p-options (org-export-backend-options parent)))
(list :options-alist (append options p-options)))
(and menu-entry (list :menu-entry menu-entry))))
(org-export-barf-if-invalid-backend parent)
;; Register back-end.
(let ((registeredp (assq child org-export-registered-backends)))
(if registeredp (setcdr registeredp contents)
(push (cons child contents) org-export-registered-backends)))
;; Tell parser to not parse EXPORT-BLOCK blocks.
(when export-block
(mapc
(lambda (name)
(add-to-list 'org-element-block-name-alist
`(,name . org-element-export-block-parser)))
export-block))))
(defun org-export-backend-parent (backend)
"Return back-end from which BACKEND is derived, or nil."
(plist-get (cdr (assq backend org-export-registered-backends)) :parent))
(defun org-export-backend-filters (backend)
"Return filters for BACKEND."
(plist-get (cdr (assq backend org-export-registered-backends))
:filters-alist))
(defun org-export-backend-menu (backend)
"Return menu entry for BACKEND."
(plist-get (cdr (assq backend org-export-registered-backends))
:menu-entry))
(defun org-export-backend-options (backend)
"Return export options for BACKEND."
(plist-get (cdr (assq backend org-export-registered-backends))
:options-alist))
(defun org-export-backend-translate-table (backend)
"Return translate table for BACKEND."
(plist-get (cdr (assq backend org-export-registered-backends))
:translate-alist))
(defun org-export-barf-if-invalid-backend (backend)
"Signal an error if BACKEND isn't defined."
(unless (org-export-backend-translate-table backend)
(error "Unknown \"%s\" back-end: Aborting export" backend)))
(defun org-export-derived-backend-p (backend &rest backends)
"Non-nil if BACKEND is derived from one of BACKENDS."
(let ((parent backend))
(while (and (not (memq parent backends))
(setq parent (org-export-backend-parent parent))))
parent))
(org-export-register-backend
(org-export-create-backend :name child
:parent parent
:transcoders transcoders
:options options
:filters filters
:blocks blocks
:menu menu-entry))))
@ -1448,14 +1486,15 @@ The back-end could then be called with, for example:
;; `org-export--get-subtree-options' and
;; `org-export--get-inbuffer-options'
;;
;; Also, `org-export--install-letbind-maybe' takes care of the part
;; relative to "#+BIND:" keywords.
;; Also, `org-export--list-bound-variables' collects bound variables
;; along with their value in order to set them as buffer local
;; variables later in the process.
(defun org-export-get-environment (&optional backend subtreep ext-plist)
"Collect export options from the current buffer.
Optional argument BACKEND is a symbol specifying which back-end
specific options to read, if any.
Optional argument BACKEND is an export back-end, as returned by
`org-export-create-backend'.
When optional argument SUBTREEP is non-nil, assume the export is
done against the current sub-tree.
@ -1481,8 +1520,7 @@ inferior to file-local settings."
(list
:back-end
backend
:translate-alist
(org-export-backend-translate-table backend)
:translate-alist (org-export-get-all-transcoders backend)
:footnote-definition-alist
;; Footnotes definitions must be collected in the original
;; buffer, as there's no insurance that they will still be in
@ -1518,11 +1556,12 @@ inferior to file-local settings."
(defun org-export--parse-option-keyword (options &optional backend)
"Parse an OPTIONS line and return values as a plist.
Optional argument BACKEND is a symbol specifying which back-end
Optional argument BACKEND is an export back-end, as returned by,
e.g., `org-export-create-backend'. It specifies which back-end
specific items to read, if any."
(let* ((all
;; Priority is given to back-end specific options.
(append (and backend (org-export-backend-options backend))
(append (and backend (org-export-get-all-options backend))
org-export-options-alist))
plist)
(dolist (option all)
@ -1542,7 +1581,8 @@ specific items to read, if any."
(defun org-export--get-subtree-options (&optional backend)
"Get export options in subtree at point.
Optional argument BACKEND is a symbol specifying back-end used
Optional argument BACKEND is an export back-end, as returned by,
e.g., `org-export-create-backend'. It specifies back-end used
for export. Return options as a plist."
;; For each buffer keyword, create a headline property setting the
;; same property in communication channel. The name for the property
@ -1594,7 +1634,7 @@ for export. Return options as a plist."
(t value)))))))))
;; Look for both general keywords and back-end specific
;; options, with priority given to the latter.
(append (and backend (org-export-backend-options backend))
(append (and backend (org-export-get-all-options backend))
org-export-options-alist)))
;; Return value.
plist)))
@ -1602,7 +1642,8 @@ for export. Return options as a plist."
(defun org-export--get-inbuffer-options (&optional backend)
"Return current buffer export options, as a plist.
Optional argument BACKEND, when non-nil, is a symbol specifying
Optional argument BACKEND, when non-nil, is an export back-end,
as returned by, e.g., `org-export-create-backend'. It specifies
which back-end specific options should also be read in the
process.
@ -1612,7 +1653,7 @@ Assume buffer is in Org mode. Narrowing, if any, is ignored."
(case-fold-search t)
(options (append
;; Priority is given to back-end specific options.
(and backend (org-export-backend-options backend))
(and backend (org-export-get-all-options backend))
org-export-options-alist))
(regexp (format "^[ \t]*#\\+%s:"
(regexp-opt (nconc (delq nil (mapcar 'cadr options))
@ -1725,12 +1766,13 @@ name."
(defun org-export--get-global-options (&optional backend)
"Return global export options as a plist.
Optional argument BACKEND, if non-nil, is a symbol specifying
Optional argument BACKEND, if non-nil, is an export back-end, as
returned by, e.g., `org-export-create-backend'. It specifies
which back-end specific export options should also be read in the
process."
(let (plist
;; Priority is given to back-end specific options.
(all (append (and backend (org-export-backend-options backend))
(all (append (and backend (org-export-get-all-options backend))
org-export-options-alist)))
(dolist (cell all plist)
(let ((prop (car cell)))
@ -2058,11 +2100,10 @@ a tree with a select tag."
;; back-end output. It takes care of filtering out elements or
;; objects according to export options and organizing the output blank
;; lines and white space are preserved. The function memoizes its
;; results, so it is cheap to call it within translators.
;; results, so it is cheap to call it within transcoders.
;;
;; It is possible to modify locally the back-end used by
;; `org-export-data' or even use a temporary back-end by using
;; `org-export-data-with-translations' and
;; `org-export-data-with-backend'.
;;
;; Internally, three functions handle the filtering of objects and
@ -2190,24 +2231,6 @@ Return transcoded string."
results)))
(plist-get info :exported-data))))))
(defun org-export-data-with-translations (data translations info)
"Convert DATA into another format using a given translation table.
DATA is an element, an object, a secondary string or a string.
TRANSLATIONS is an alist between element or object types and
a functions handling them. See `org-export-define-backend' for
more information. INFO is a plist used as a communication
channel."
(org-export-data
data
;; Set-up a new communication channel with TRANSLATIONS as the
;; translate table and a new hash table for memoization.
(org-combine-plists
info
(list :translate-alist translations
;; Size of the hash table is reduced since this function
;; will probably be used on short trees.
:exported-data (make-hash-table :test 'eq :size 401)))))
(defun org-export-data-with-backend (data backend info)
"Convert DATA into BACKEND format.
@ -2217,9 +2240,18 @@ channel.
Unlike to `org-export-with-backend', this function will
recursively convert DATA using BACKEND translation table."
(org-export-barf-if-invalid-backend backend)
(org-export-data-with-translations
data (org-export-backend-translate-table backend) info))
(when (symbolp backend) (setq backend (org-export-get-backend backend)))
(org-export-data
data
;; Set-up a new communication channel with translations defined in
;; BACKEND as the translate table and a new hash table for
;; memoization.
(org-combine-plists
info
(list :translate-alist (org-export-get-all-transcoders backend)
;; Size of the hash table is reduced since this function
;; will probably be used on short trees.
:exported-data (make-hash-table :test 'eq :size 401)))))
(defun org-export--interpret-p (blob info)
"Non-nil if element or object BLOB should be interpreted during export.
@ -2713,18 +2745,19 @@ channel, as a plist. It must return a string or nil.")
"Call every function in FILTERS.
Functions are called with arguments VALUE, current export
back-end and INFO. A function returning a nil value will be
skipped. If it returns the empty string, the process ends and
back-end's name and INFO. A function returning a nil value will
be skipped. If it returns the empty string, the process ends and
VALUE is ignored.
Call is done in a LIFO fashion, to be sure that developer
specified filters, if any, are called first."
(catch 'exit
(dolist (filter filters value)
(let ((result (funcall filter value (plist-get info :back-end) info)))
(cond ((not result) value)
((equal value "") (throw 'exit nil))
(t (setq value result)))))))
(let ((backend-name (plist-get info :back-end)))
(dolist (filter filters value)
(let ((result (funcall filter value backend-name info)))
(cond ((not result) value)
((equal value "") (throw 'exit nil))
(t (setq value result))))))))
(defun org-export-install-filters (info)
"Install filters properties in communication channel.
@ -2755,7 +2788,7 @@ Return the updated communication channel."
plist key
(if (atom value) (cons value (plist-get plist key))
(append value (plist-get plist key))))))))
(org-export-backend-filters (plist-get info :back-end)))
(org-export-get-all-filters (plist-get info :back-end)))
;; Return new communication channel.
(org-combine-plists info plist)))
@ -2891,6 +2924,10 @@ The function assumes BUFFER's major mode is `org-mode'."
(backend &optional subtreep visible-only body-only ext-plist)
"Transcode current Org buffer into BACKEND code.
BACKEND is either an export back-end, as returned by, e.g.,
`org-export-create-backend', or a symbol referring to
a registered back-end.
If narrowing is active in the current buffer, only transcode its
narrowed part.
@ -2911,6 +2948,7 @@ with external parameters overriding Org default settings, but
still inferior to file-local settings.
Return code as a string."
(when (symbolp backend) (setq backend (org-export-get-backend backend)))
(org-export-barf-if-invalid-backend backend)
(save-excursion
(save-restriction
@ -2943,8 +2981,9 @@ Return code as a string."
;; created, where include keywords, macros are expanded and
;; code blocks are evaluated.
(org-export-with-buffer-copy
;; Run first hook with current back-end as argument.
(run-hook-with-args 'org-export-before-processing-hook backend)
;; Run first hook with current back-end's name as argument.
(run-hook-with-args 'org-export-before-processing-hook
(org-export-backend-name backend))
(org-export-expand-include-keyword)
;; Update macro templates since #+INCLUDE keywords might have
;; added some new ones.
@ -2954,10 +2993,11 @@ Return code as a string."
;; Update radio targets since keyword inclusion might have
;; added some more.
(org-update-radio-target-regexp)
;; Run last hook with current back-end as argument.
;; Run last hook with current back-end's name as argument.
(goto-char (point-min))
(save-excursion
(run-hook-with-args 'org-export-before-parsing-hook backend))
(run-hook-with-args 'org-export-before-parsing-hook
(org-export-backend-name backend)))
;; Update communication channel with environment. Also
;; install user's and developer's filters.
(setq info
@ -2980,9 +3020,10 @@ Return code as a string."
;; Call options filters and update export options. We do not
;; use `org-export-filter-apply-functions' here since the
;; arity of such filters is different.
(dolist (filter (plist-get info :filter-options))
(let ((result (funcall filter info backend)))
(when result (setq info result))))
(let ((backend-name (org-export-backend-name backend)))
(dolist (filter (plist-get info :filter-options))
(let ((result (funcall filter info backend-name)))
(when result (setq info result)))))
;; Parse buffer and call parse-tree filter on it.
(setq tree
(org-export-filter-apply-functions
@ -3018,7 +3059,9 @@ Return code as a string."
(backend buffer &optional subtreep visible-only body-only ext-plist)
"Call `org-export-as' with output to a specified buffer.
BACKEND is the back-end used for transcoding, as a symbol.
BACKEND is either an export back-end, as returned by, e.g.,
`org-export-create-backend', or a symbol referring to
a registered back-end.
BUFFER is the output buffer. If it already exists, it will be
erased first, otherwise, it will be created.
@ -3046,8 +3089,10 @@ to kill ring. Return buffer."
(backend file &optional subtreep visible-only body-only ext-plist)
"Call `org-export-as' with output to a specified file.
BACKEND is the back-end used for transcoding, as a symbol. FILE
is the name of the output file, as a string.
BACKEND is either an export back-end, as returned by, e.g.,
`org-export-create-backend', or a symbol referring to
a registered back-end. FILE is the name of the output file, as
a string.
Optional arguments SUBTREEP, VISIBLE-ONLY, BODY-ONLY and
EXT-PLIST are similar to those used in `org-export-as', which
@ -3074,6 +3119,10 @@ to kill ring. Return output file's name."
(defun org-export-string-as (string backend &optional body-only ext-plist)
"Transcode STRING into BACKEND code.
BACKEND is either an export back-end, as returned by, e.g.,
`org-export-create-backend', or a symbol referring to
a registered back-end.
When optional argument BODY-ONLY is non-nil, only return body
code, without preamble nor postamble.
@ -3089,7 +3138,10 @@ Return code as a string."
;;;###autoload
(defun org-export-replace-region-by (backend)
"Replace the active region by its export to BACKEND."
"Replace the active region by its export to BACKEND.
BACKEND is either an export back-end, as returned by, e.g.,
`org-export-create-backend', or a symbol referring to
a registered back-end."
(if (not (org-region-active-p))
(user-error "No active region to replace")
(let* ((beg (region-beginning))
@ -3103,10 +3155,10 @@ Return code as a string."
(defun org-export-insert-default-template (&optional backend subtreep)
"Insert all export keywords with default values at beginning of line.
BACKEND is a symbol representing the export back-end for which
specific export options should be added to the template, or
`default' for default template. When it is nil, the user will be
prompted for a category.
BACKEND is a symbol referring to the name of a registered export
back-end, for which specific export options should be added to
the template, or `default' for default template. When it is nil,
the user will be prompted for a category.
If SUBTREEP is non-nil, export configuration will be set up
locally for the subtree through node properties."
@ -3115,17 +3167,22 @@ locally for the subtree through node properties."
(when (and subtreep (org-before-first-heading-p))
(user-error "No subtree to set export options for"))
(let ((node (and subtreep (save-excursion (org-back-to-heading t) (point))))
(backend (or backend
(intern
(org-completing-read
"Options category: "
(cons "default"
(mapcar (lambda (b) (symbol-name (car b)))
org-export-registered-backends))))))
(backend
(or backend
(intern
(org-completing-read
"Options category: "
(cons "default"
(mapcar (lambda (b)
(symbol-name (org-export-backend-name b)))
org-export--registered-backends))))))
options keywords)
;; Populate OPTIONS and KEYWORDS.
(dolist (entry (if (eq backend 'default) org-export-options-alist
(org-export-backend-options backend)))
(dolist (entry (cond ((eq backend 'default) org-export-options-alist)
((org-export-backend-p backend)
(org-export-get-all-options backend))
(t (org-export-get-all-options
(org-export-backend-name backend)))))
(let ((keyword (nth 1 entry))
(option (nth 2 entry)))
(cond
@ -3502,16 +3559,20 @@ Caption lines are separated by a white space."
;; back-end, it may be used as a fall-back function once all specific
;; cases have been treated.
(defun org-export-with-backend (back-end data &optional contents info)
"Call a transcoder from BACK-END on DATA.
CONTENTS, when non-nil, is the transcoded contents of DATA
element, as a string. INFO, when non-nil, is the communication
channel used for export, as a plist.."
(org-export-barf-if-invalid-backend back-end)
(defun org-export-with-backend (backend data &optional contents info)
"Call a transcoder from BACKEND on DATA.
BACKEND is an export back-end, as returned by, e.g.,
`org-export-create-backend', or a symbol referring to
a registered back-end. DATA is an Org element, object, secondary
string or string. CONTENTS, when non-nil, is the transcoded
contents of DATA element, as a string. INFO, when non-nil, is
the communication channel used for export, as a plist."
(when (symbolp backend) (setq backend (org-export-get-backend backend)))
(org-export-barf-if-invalid-backend backend)
(let ((type (org-element-type data)))
(if (memq type '(nil org-data)) (error "No foreign transcoder available")
(let ((transcoder
(cdr (assq type (org-export-backend-translate-table back-end)))))
(cdr (assq type (org-export-get-all-transcoders backend)))))
(if (functionp transcoder) (funcall transcoder data contents info)
(error "No foreign transcoder available"))))))
@ -5849,43 +5910,31 @@ back to standard interface."
(lambda (value)
;; Fontify VALUE string.
(org-propertize value 'face 'font-lock-variable-name-face)))
;; Prepare menu entries by extracting them from
;; `org-export-registered-backends', and sorting them by
;; access key and by ordinal, if any.
(backends
(sort
(sort
(delq nil
(mapcar
(lambda (b)
(let ((name (car b)))
(catch 'ignored
;; Ignore any back-end belonging to
;; `org-export-invisible-backends' or derived
;; from one of them.
(dolist (ignored org-export-invisible-backends)
(when (org-export-derived-backend-p name ignored)
(throw 'ignored nil)))
(org-export-backend-menu name))))
org-export-registered-backends))
(lambda (a b)
(let ((key-a (nth 1 a))
(key-b (nth 1 b)))
(cond ((and (numberp key-a) (numberp key-b))
(< key-a key-b))
((numberp key-b) t)))))
(lambda (a b) (< (car a) (car b)))))
;; Prepare menu entries by extracting them from registered
;; back-ends and sorting them by access key and by ordinal,
;; if any.
(entries
(sort (sort (delq nil
(mapcar 'org-export-backend-menu
org-export--registered-backends))
(lambda (a b)
(let ((key-a (nth 1 a))
(key-b (nth 1 b)))
(cond ((and (numberp key-a) (numberp key-b))
(< key-a key-b))
((numberp key-b) t)))))
'car-less-than-car))
;; Compute a list of allowed keys based on the first key
;; pressed, if any. Some keys
;; (?^B, ?^V, ?^S, ?^F, ?^A, ?&, ?# and ?q) are always
;; available.
(allowed-keys
(nconc (list 2 22 19 6 1)
(if (not first-key) (org-uniquify (mapcar 'car backends))
(if (not first-key) (org-uniquify (mapcar 'car entries))
(let (sub-menu)
(dolist (backend backends (sort (mapcar 'car sub-menu) '<))
(when (eq (car backend) first-key)
(setq sub-menu (append (nth 2 backend) sub-menu))))))
(dolist (entry entries (sort (mapcar 'car sub-menu) '<))
(when (eq (car entry) first-key)
(setq sub-menu (append (nth 2 entry) sub-menu))))))
(cond ((eq first-key ?P) (list ?f ?p ?x ?a))
((not first-key) (list ?P)))
(list ?& ?#)
@ -5944,7 +5993,7 @@ back to standard interface."
(nth 1 sub-entry)))
sub-menu "")
(when (zerop (mod index 2)) "\n"))))))))
backends ""))
entries ""))
;; Publishing menu is hard-coded.
(format "\n[%s] Publish
[%s] Current file [%s] Current project
@ -5979,7 +6028,7 @@ back to standard interface."
;; UI, display an intrusive help buffer.
(if expertp
(org-export--dispatch-action
expert-prompt allowed-keys backends options first-key expertp)
expert-prompt allowed-keys entries options first-key expertp)
;; At first call, create frame layout in order to display menu.
(unless (get-buffer "*Org Export Dispatcher*")
(delete-other-windows)
@ -6002,15 +6051,15 @@ back to standard interface."
(set-window-start nil pos)))
(org-fit-window-to-buffer)
(org-export--dispatch-action
standard-prompt allowed-keys backends options first-key expertp))))
standard-prompt allowed-keys entries options first-key expertp))))
(defun org-export--dispatch-action
(prompt allowed-keys backends options first-key expertp)
(prompt allowed-keys entries options first-key expertp)
"Read a character from command input and act accordingly.
PROMPT is the displayed prompt, as a string. ALLOWED-KEYS is
a list of characters available at a given step in the process.
BACKENDS is a list of menu entries. OPTIONS, FIRST-KEY and
ENTRIES is a list of menu entries. OPTIONS, FIRST-KEY and
EXPERTP are the same as defined in `org-export--dispatch-ui',
which see.
@ -6067,9 +6116,9 @@ options as CDR."
first-key expertp))
;; Action selected: Send key and options back to
;; `org-export-dispatch'.
((or first-key (functionp (nth 2 (assq key backends))))
((or first-key (functionp (nth 2 (assq key entries))))
(cons (cond
((not first-key) (nth 2 (assq key backends)))
((not first-key) (nth 2 (assq key entries)))
;; Publishing actions are hard-coded. Send a special
;; signal to `org-export-dispatch'.
((eq first-key ?P)
@ -6082,10 +6131,10 @@ options as CDR."
;; path. Indeed, derived backends can share the same
;; FIRST-KEY.
(t (catch 'found
(mapc (lambda (backend)
(let ((match (assq key (nth 2 backend))))
(mapc (lambda (entry)
(let ((match (assq key (nth 2 entry))))
(when match (throw 'found (nth 2 match)))))
(member (assq first-key backends) backends)))))
(member (assq first-key entries) entries)))))
options))
;; Otherwise, enter sub-menu.
(t (org-export--dispatch-ui options key expertp)))))

File diff suppressed because it is too large Load Diff