emacs/layers.personal/orgtools/local/ox-ravel/ox-ravel.el
2018-04-07 10:54:04 +08:00

823 lines
30 KiB
EmacsLisp

;;; ox-ravel.el --- Sweave/knit/brew document maker for orgmode
;; Copyright (C) 2012---2016 Charles C. Berry
;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;;
;; Several exporters are provided for translating from
;; Org to formats for reproducible research using
;; document generating engines such as Sweave, brew,
;; knitr, rmarkdown, et cetera. Typically, R src blocks
;; are converted to `code chunks' in the desired format
;; and the rest of the Org document is translated to
;; latex, html, markdown, or some other document format.
;;
;; See ox-ravel.org in the orgmode-accessories archive on
;; github for details. Also see demos.org and other
;; *.org files for examples of usage.
;;; Code:
;;
;;; Requisites and Declarations
(eval-when-compile (require 'cl-lib))
(require 'ox)
(declare-function org-babel-expand-body:R "ob-R.el" )
;; defconst-org-babel-header-args:ravel
;; #+NAME: defconst-org-babel-header-args-ravel
(defconst org-babel-header-args:ravel
'(
(ravel . :any)
(ravel-style . :any)
(engine . :any))
"Ravel-specific header arguments.")
;; org-lint org-lint needs these
(eval-after-load 'ob-core
'(mapc (lambda (x)
(add-to-list
'org-babel-common-header-args-w-values x))
org-babel-header-args:ravel))
(eval-after-load 'ob-core
'(mapc (lambda (x)
(add-to-list
'org-babel-header-arg-names (car x)))
org-babel-header-args:ravel))
;; defvar-org-ravel-style
;; #+NAME: defvar-org-ravel-style
(defvar org-ravel-style nil
"The default style to use for constructing chunks.
Can be buffer-local, and is usually set by the export dispatcher.")
(make-variable-buffer-local 'org-ravel-style)
;; defvar-org-ravel-run
;; #+NAME: defvar-org-ravel-run
(defvar-local org-ravel-run nil
"If ravel is to be run on src blocks, this will be a list like
'(\"R\") or '(\"R\" \"python\" \"awk\")
and usually set (by the export dispatcher) to `org-ravel-engines'.
Set this as buffer/file local for demos or debugging.")
;; defcustom-org-ravel-engines
;; #+NAME: defcustom-org-ravel-engines
(defcustom org-ravel-engines '(("R"))
"Use these engines in forming ravel chunks.
Typically, `org-ravel-run' will default to these. It can be
buffer-local. These engines are recognized by `knitr':
`R' `python' `awk' `ruby' `haskell' `bash' `perl' `dot'
`tikz' `sas' `coffeescript', `c', `Rcpp', and `polyglot'.
Each alist CONS cell has the language (as a string) for the CAR and
any cdr is cons-ed to the ravel attributes.
Buffer local values are allowed."
:group 'org-export-ravel
:type '(set :greedy t
(const :tag " R" ("R") )
(const :tag " c" ("c" . "engine='c'"))
(const :tag " rcpp" ("c++" . "engine='Rcpp'"))
(const :tag " C" ("C" . "engine='c'"))
(const :tag " Rcpp" ("C++" . "engine='Rcpp'"))
(const :tag " Python" ("python" . "engine='python'"))
(const :tag " AWK" ("awk" . "engine='awk'"))
(const :tag " Ruby" ("ruby" . "engine='ruby'"))
(const :tag " Haskell" ("haskell" . "engine='haskell'"))
(const :tag " bash" ("bash" . "engine='bash'"))
(const :tag " perl" ("perl" . "engine='perl'"))
(const :tag " dot" ("dot" . "engine='dot'"))
(const :tag " TikZ" ("tikz" . "engine='tikz'"))
(const :tag " SAS" ("sas" . "engine='sas'"))
(const :tag " CoffeeScript"
("coffeescript" . "engine='coffeescript'"))
(const :tag " Polyglot" ("polyglot" . "engine='polyglot'"))
(cons :tag " Other" string string)))
(make-variable-buffer-local 'org-ravel-engines)
;; defvar-org-ravel-style-alist
;; #+NAME: defcustom-org-ravel-style-alist
(defgroup org-export-ravel nil
"Options for exporting Org mode files via Ravel."
:tag "Org Export Ravel"
:group 'org-export)
(defcustom org-ravel-style-alist
'((rnw . (org-ravel-block-rnw org-ravel-inline-rnw ".Rnw"))
(brew . (org-ravel-block-brew org-ravel-inline-brew ".Rbrew"))
(tex . (org-ravel-block-tex org-ravel-inline-tex ".Rtex"))
(html . (org-ravel-block-html org-ravel-inline-html ".Rhtml"))
(md . (org-ravel-block-md org-ravel-inline-md ".Rmd"))
(braces . (org-ravel-block-braces org-ravel-inline-braces ".Rtmpl"))
(rst . (org-ravel-block-rst org-ravel-inline-rst ".Rrst")))
"The Chunk Style Alist to use in formatting Ravel output.
The key of each element is matched by the `:ravel-style' property
of a document, if specified, or by the default `:ravel-style' of
the exporter selected.
The value of each pair is a list of three elements:
- the function that formats src blocks
- the function that formats inline src blocks
- a string giving the file extension. "
:group 'org-export-ravel
:type '(alist
:key-type (symbol :tag "Ravel Style")
:value--type (list :tag "Chunk Defn"
(function :tag "block coder")
(function :tag "inline coder")
(string :tag "File extension"))))
;; defvar-org-ravel-backend-parent
(defvar org-ravel-backend-parent nil
"If ravel is running, this variable will contain the name of the parent.")
;; defun-org-babel-expand-body:ravel
(defun org-babel-expand-body:ravel (body params &optional var-lines)
"Use native `org-babel-expand-body' for src-block engine if
there is one to format BODY as per PARAMS."
(let*
((engine-cdr (cdr (assq :engine params)))
(engine (and engine-cdr
(replace-regexp-in-string
"engine='\\([^']+\\)'" "\\1" engine-cdr)))
(expand-cmd
(intern (concat "org-babel-expand-body:" engine))))
(cond
((and engine (fboundp expand-cmd))
(funcall expand-cmd body params))
(engine (org-babel-expand-body:generic body params))
(t (org-babel-expand-body:R body params)))))
;; defun-org-ravel-rewrap
;; Wrap the results of `org-babel-execute:ravel' in a
;; :#+BEGIN_EXPORT RAVEL ... #+END_EXPORT block.
;; #+NAME: defun-org-ravel-rewrap
(defun org-ravel-rewrap (retval &optional inline engine-cdr)
"(Re)Set `:wrap', `:results', `:exports', amd `:engine'
header args to values ravel uses. INLINE settings
differ. ENGINE-CDR gives the engine string, if any.
Argument RETVAL is the vslue of `org-babel-get-src-block-info'..
The original header args `:exports', `:wrap', `:file', `:file-ext', and
`:results' get suffixed with `-arg'. Block/snippet style
functions can find them in `R-HEADERS-ATTR'. "
(let ((n2r (nth 2 retval)))
(cl-loop
for carname in
'(:exports :results :wrap :file :file-ext) do
(let ((elt (assq carname n2r)))
(if elt
(setcar elt (intern (format "%S-arg" carname))))))
;; end do
(setf (nth 2 retval)
(append
`((:results . "replace")
(:wrap . ,(if inline "ravel" "EXPORT RAVEL"))
(:exports . "results")
(:engine . ,engine-cdr))
n2r))))
;; defvar-org-ravel-no-confirm-for-ravel
;; Confirmation of ravel `execution' is a nuisance --- and no code is
;; actually run --- so disable confirmations for `ravel' src blocks.
;; This can be overridden by `(setq org-ravel-no-confirm-for-ravel t)' if
;; ever needed.
;; Maybe need to add check if (functionp org-confirm-babel-evaluate) is
;; nil in which case, I do not reset it.
;; #+NAME: defvar-org-ravel-no-confirm-for-ravel
(defvar org-ravel-no-confirm-for-ravel
(lambda (language body)
(if (string= language "ravel") nil t))
"Do not confirm if LANGUAGE is `ravel'.")
(defun org-ravel-reset-confirm (value)
"Revert `org-confirm-babel-evaluate' as buffer local VALUE."
(when org-confirm-babel-evaluate
(setf org-confirm-babel-evaluate
value)))
;; defun-org-babel-execute:ravel
;; `org-babel-execute:ravel' calls formatting functions for the code. No
;; actual code is run. Also need to add some kind of alias for edit modes
;; if Rcpp is to be supported. Like `(defalias 'Rcpp-mode 'c++-mode)'
;; #+NAME: defun-org-babel-execute-ravel
(defun org-babel-execute:ravel (body params)
"Format BODY as ravel according to PARAMS."
(save-excursion
(if (string= "none" (cdr (assoc :exports params)))
""
(let*
((oec (org-element-context))
(ravel-attr (org-element-property :attr_ravel oec))
(type (org-element-type oec))
;; Need (org-babel-params-from-properties "ravel") here as
;; parsing was done on "R" or other language.
(headers (apply #'org-babel-merge-params
(append
(org-babel-params-from-properties "ravel")
(list params))))
(ravelarg (cdr (assoc :ravel headers)))
(engine (cdr (assoc :engine headers)))
(ravelstyle (cdr (assoc :ravel-style headers)))
(label (org-element-property :name oec))
(non-ravelargs (assq-delete-all :ravel headers))
(chunk-style
(org-ravel-get-style ravelstyle))
(body (org-remove-indentation body))
(full-body
(org-babel-expand-body:ravel body params)))
(when engine
(setq ravel-attr
(cons engine
ravel-attr)))
(if (memq type '(inline-src-block inline-babel-call))
(org-ravel-snippetize chunk-style ravelarg non-ravelargs full-body)
(org-ravel-blockify chunk-style label ravelarg ravel-attr
non-ravelargs full-body))))))
;; defun-org-ravel-snippetize/blockify
;; Call the chunk-style functions to format the code.
;; #+NAME: defun-org-ravel-snippetize
(defun org-ravel-snippetize (chunk-style ravelarg r-headers-attr body)
"Format an inline src block.
Use CHUNK-STYLE, RAVELARG, and R-HEADERS-ATTR (often ignored) to
format BODY, then wrap it inside an export snippet."
(funcall (nth 1 chunk-style)
ravelarg r-headers-attr body))
(defun org-ravel-blockify
(chunk-style label ravelarg ravel-attr non-ravelargs body)
"Format a src block.
Use CHUNK-STYLE, LABEL, RAVELARG, RAVEL-ATTR and
NON-RAVELARGS (typically ignored) to format BODY and wrap it
inside an export block."
(funcall (nth 0 chunk-style) label ravelarg
ravel-attr non-ravelargs body))
;; defun-org-ravel-get-style
;; #+NAME: defun-org-ravel-get-style
(defun org-ravel-get-style (style-from-header)
"Return the chunk style for STYLE-FROM-HEADER.
Possibly find it in properties or use `org-ravel-style' by
default."
(or
(assoc-default
(or style-from-header
(cdr (assoc
:ravel-style
(org-babel-parse-header-arguments
(org-entry-get (point)
"header-args:ravel"
'inherit))))
org-ravel-style)
org-ravel-style-alist 'string=)
(user-error "Ravel-style: %S not found -- Consult `org-ravel-style-alist'"
style-from-header)))
;; defun-org-ravel-attr-plus-header
;; #+NAME: defun-org-ravel-attr-plus-header
(defun org-ravel-attr-plus-header
(label ravelarg ravel-attr)
"Separate LABEL, RAVELARG, and RAVEL-ATTR by commas."
(mapconcat #'identity
(delete nil
(cons label
(cons ravelarg ravel-attr))) ", "))
;; defmacro-org-ravel-style-x
;; #+NAME: defmacro-org-ravel-style-x
(defmacro org-ravel-style-x (x xblock xinline &optional xcode)
"Make style functions.
The functions are `org-ravel-block-X' and `org-ravel-inline-X'
where X names the style, XBLOCK gives the block format, XINLINE gives the
inline format, and XCODE is an optional line prefix.
`org-ravel-block-X' defines the Chunk code style. It's arguments are
LABEL - the chunk name (which will be sanitized by
substituting `_' for any character not allowed as a
chunk label by Sweave),
RAVEL - header args as a string,
ATTR-RAVEL - attributes to be combined with RAVEL,
R-HEADERS-ATTR - other headers from Babel as a string parseable
by `org-babel-parse-header-arguments',
SRC-CODE is the code from the block.
`org-ravel-inline-X' defines the inline code style. It's arguments
are RAVEL, R-HEADERS-ATTR, SRC-CODE as above. Note that only SRC-CODE is
used in this macro, but other arguments may be used in hand tooled inline
style functions."
(let ((blk-args
'(label ravel attr-ravel r-headers-attr src-code))
(inline-args '(ravel r-headers-attr src-code))
(blk-body
`(let* ((label
(if label
(replace-regexp-in-string "[^[:alnum:]#+-_.]" "_" label)))
(ravel (org-ravel-attr-plus-header label ravel attr-ravel)))
,(if xcode
`(format ,xblock ravel
(replace-regexp-in-string "^" ,xcode src-code))
`(format ,xblock ravel src-code))))
(inline-body `(format ,xinline src-code))
(bname (concat "org-ravel-block-" x))
(iname (concat "org-ravel-inline-" x)))
(defalias (intern bname)
(list 'lambda blk-args blk-body)
(concat "Run this:\n\n" (pp-to-string blk-body)))
(defalias (intern iname)
(list 'lambda inline-args inline-body)
(concat "Run this:\n\n" (pp-to-string inline-body)))
(format "Functions: %s and %s" bname iname)))
;; defun-org-ravel-format-brew-spec
;; #+NAME: defun-org-ravel-format-brew-spec
(defun org-ravel-format-brew-spec (&optional spec)
"Check a brew SPEC, escape % signs, and add a %s spec."
(let
((spec (or spec "<% %>")))
(if (string-match
"<\\(%+\\)\\([=]?\\)\\(.+?\\)\\([{}]?[ ]*-?\\)\\(%+\\)>"
spec)
(let (
(opct (match-string 1 spec))
(eqsign (match-string 2 spec))
(filler (match-string 3 spec))
(enddash (match-string 4 spec))
(clpct (match-string 5 spec)))
(if (string= opct clpct)
(concat "<" opct opct eqsign " %s " enddash clpct clpct ">")
(error "Percent signs do not balance:%s" spec)))
(error "Invalid spec:%s" spec))))
;; defun-org-ravel-block-brew
;; #+NAME: defun-org-ravel-block-brew
(defun org-ravel-block-brew (label ravel attr_ravel r-headers-attr src-code)
"Define the chunk style for brew.
LABEL is the chunk name, RAVEL is the collection of ravel args as
a string, ATTR_RAVEL and R-HEADERS-ATTR are ignored here,
SRC-CODE is the code from the block."
(format (org-ravel-format-brew-spec ravel) src-code))
(defun org-ravel-inline-brew (ravel r-headers-attr src-code)
"Define the inline-src style for brew.
RAVEL is the collection of ravel args as a string, R-HEADERS-ATTR
is the collection of headers from Babel as a string parseable by
`org-babel-parse-header-arguments', SRC-CODE is the code from the
block."
(format (org-ravel-format-brew-spec
(or ravel "<%= code -%>"))
src-code))
;; org-ravel-style-x-rnw
;; #+NAME: org-ravel-style-x-rnw
(org-ravel-style-x "rnw"
"<<%s>>=\n%s\n@ %%def"
"\\Sexpr{ %s }")
;; org-ravel-style-x-tex
;; #+NAME: org-ravel-style-x-tex
(org-ravel-style-x "tex"
"%% begin.rcode( %s )\n%s\n%% end.code"
"\\rinline{ %s }"
"%")
;; org-ravel-style-x-html
;; #+NAME: org-ravel-style-x-html
(org-ravel-style-x "html"
"<!--begin.rcode %s \n%s\nend.rcode-->"
"<!--rinline %s -->")
;; org-ravel-style-x-md
;; #+NAME: org-ravel-style-x-md
(org-ravel-style-x "md"
"```{r %s }\n%s \n```"
"`r %s `")
;; org-ravel-style-x-braces
;; #+NAME: org-ravel-style-x-braces
(org-ravel-style-x "braces"
"{{%0.0s%s}}"
"{{%s}}")
;; org-ravel-style-x-rst
;; #+NAME: org-ravel-style-x-rst
(org-ravel-style-x "rst"
"..{r %s}\n%s\n.. .."
":r:`%s`"
"%")
;; defun-org-ravel-export-block
;; #+NAME: defun-org-ravel-export-block
(defun org-ravel-export-block (export-block contents info)
"Transcode a EXPORT-BLOCK element from Org to ravel.
CONTENTS is nil. INFO is a plist holding contextual information."
(if (equal (org-element-property :type export-block) "RAVEL")
(org-unescape-code-in-string
(org-element-property :value export-block))
(org-export-with-backend
org-ravel-backend-parent export-block contents info)))
;; defun-org-ravel-export-snippet
;; #+NAME: defun-org-ravel-export-snippet
(defun org-ravel-export-snippet (export-snippet contents info)
"Transcode a EXPORT-SNIPPET element from Org to ravel.
CONTENTS is nil. INFO is a plist holding contextual information."
(if (eq (org-export-snippet-backend export-snippet) 'ravel)
(org-element-property :value export-snippet)
(org-export-with-backend org-ravel-backend-parent export-snippet contents info)))
;; defun-org-ravel-create-backend
(defun org-ravel-create-backend (parent &optional style)
"Create a ravel-compliant backend from PARENT using STYLE.
Hence, (org-ravel-create-backend 'ascii \"md\") creates a backend
whose parent is ascii and default style is \"md\"."
(org-export-create-backend
:parent parent
:transcoders '((export-snippet . org-ravel-export-snippet)
(export-block . org-ravel-export-block))
:options `((:ravel-style "RAVEL_STYLE" nil ,style t))
:blocks '("RAVEL")))
;; defmacro-org-ravel-export-wrapper
;; See [[*defun-org-ravel-export-string-as][defun-org-ravel-export-string-as]] as an example of how this
;; macro is used.
(defmacro org-ravel-export-wrapper (&rest body)
"Set up the preliminaries for the BODY of an export function.
`org-ravel-export-to-file' and similar actions need to redefine
`org-babel-get-src-block-info' and restore the
function to its original value on exit, set values for
`org-ravel-run' and for `org-ravel-style', force the `backend'
to be ravel compliant and let-bind its parent as
`org-ravel-backend-parent', and (by default) turn off
confirmation for the evaluation of ravel blocks.
`(org-ravel-export-wrapper BODY)' when used inside a `defun' will
take care of these issues.
Use of this macro outside of ravel export functions is
discouraged as it can corrupt the cache used by the
`org-element-*' functions. In case of these issues,
`org-element-cache-reset' will straighten things out."
(declare (indent 1) (debug (form body)))
`(let* ((org-ravel-get-s-b-info
;; avoid recursive redefinition
(or (bound-and-true-p org-ravel-get-s-b-info)
(symbol-function
'org-babel-get-src-block-info)))
(org-ravel-lob-get-info
;; avoid recursive redefinition
(or (bound-and-true-p org-ravel-lob-get-info)
(symbol-function
'org-babel-lob-get-info)))
;; set ravel variables
(org-ravel-run
(or engines org-ravel-run org-ravel-engines))
(bk-orig
(if (symbolp backend)
(org-export-get-backend backend) backend))
(ravel-style-option
(assq :ravel-style
(org-export-backend-options bk-orig)))
(backend (if ravel-style-option bk-orig
(unless style
(message "Non ravel BACKEND might need STYLE."))
(org-ravel-create-backend
(org-export-backend-name bk-orig) style)))
(org-ravel-backend-parent (org-export-backend-parent backend))
(org-ravel-style
(or style org-ravel-style
(nth 3
(assoc :ravel-style
(org-export-backend-options
backend)))))
(org-confirm-babel-evaluate org-confirm-babel-evaluate))
;; org-babel-get-src-block-info will modify info for ravel blocks
(cl-letf
(((symbol-function 'org-babel-get-src-block-info)
(lambda (&optional light datum)
(let* ((dat (or datum (org-element-context)))
(lang (org-element-property :language dat))
(ravel-it (assoc lang org-ravel-run))
(inline (eq 'inline-src-block (org-element-type datum)))
(engine-cdr (and ravel-it (cdr ravel-it))))
(if ravel-it
(setf (nth 1 dat)
(plist-put (nth 1 dat) :language "ravel")))
(let* ((info (funcall org-ravel-get-s-b-info light dat))
(nth-2-info (nth 2 info)))
(unless (or (not ravel-it)
(member '(:exports . "none") (nth 2 info)))
;; revise headers of RAVEL src-blocks
(org-ravel-rewrap info inline engine-cdr))
;; return info for all src-blocks
info))))
((symbol-function 'org-babel-lob-get-info)
(lambda (&optional datum)
(let*
((datum (or datum (org-element-context)))
(info (funcall org-ravel-lob-get-info datum))
(lang (car info))
(ravel-it (string= lang "ravel"))
(inline (eq 'inline-babel-call (org-element-type datum))))
(unless (or (not ravel-it)
(member '(:exports . "none") (nth 2 info)))
;; revise headers of RAVEL src-blocks
(org-ravel-rewrap info inline))
info))))
,@body)))
;; defun-org-ravel-export-string-as
;; #+NAME: defun-org-ravel-export-string-as
(defun org-ravel-export-string-as
(string backend &optional body-only ext-plist engines style)
"Export STRING as a string.
Use BACKEND with BODY-ONLY and EXT-PLIST, all as per
`org-export-string-as'. If non-nil, ENGINES will set
`org-ravel-run' locally. Otherwise, an attempt will be made to
replace it with `org-ravel-run' or `org-ravel-engines'. STYLE
will set `org-ravel-style' if non-nil, otherwise
`org-ravel-style' or the default for BACKEND will be used.
This function can be run by Babel to produce a string that is
used in a Babel src block.
It can run arbitrary backends if STYLE is supplied or if STRING
supplies valid values for src blocks and inline src blocks in it."
(org-ravel-export-wrapper
(org-ravel-reset-confirm
org-ravel-no-confirm-for-ravel)
(org-export-string-as string backend body-only ext-plist)))
;; defun-org-ravel-export-to-file
;; #+NAME: defun-org-ravel-export-to-file
(defun org-ravel-export-to-file
(backend &optional file async subtreep visible-only
body-only ext-plist post-process engines style)
"Export invoking ravel with BACKEND to FILE.
ASYNC must be nil, but SUBTREEP, VISIBLE-ONLY, BODY-ONLY,
EXT-PLIST, and POST-PROCESS are passed to `org-export-to-file'.
ENGINES supplies a value for `org-ravel-run' and STYLE for
`org-ravel-style'. If a backend is used that is not set up for
ravel, it usually best to use, e.g.
`(org-ravel-export-to-file
(org-ravel-create-backend 'ascii \"md\") ... )'
to create a ravel-compliant backend.
Note that `org-babel-confirm-evaluate' is set locally by `let*'
to `org-ravel-no-confirm-for-ravel', which holds a `lambda'
function. To override this, create a variable with that name."
(org-ravel-export-wrapper
(let ((file (or file
(org-export-output-file-name
(org-ravel-extension org-ravel-style) subtreep))))
(when async (user-error "ASYNC not allow for ravel"))
(org-ravel-reset-confirm org-ravel-no-confirm-for-ravel)
(org-export-to-file backend file async subtreep visible-only
body-only ext-plist post-process))))
;; defun-org-ravel-export-to-buffer
;; #+NAME: defun-org-ravel-export-to-buffer
(defun org-ravel-export-to-buffer
(backend &optional buffer async subtreep visible-only
body-only ext-plist post-process engines style)
"Export invoking ravel using BACKEND to BUFFER.
ASYNC must be nil, but SUBTREEP, VISIBLE-ONLY, BODY-ONLY,
EXT-PLIST, and POST-PROCESS are passed to `org-export-to-buffer'.
ENGINES supplies a value for `org-ravel-run' and STYLE for
`org-ravel-style'. If a backend is used that is not set up for
ravel, it usually best to use, e.g.
`(org-ravel-export-to-buffer
(org-ravel-create-backend 'ascii \"md\") ... )'
to create a ravel-compliant backend.
Note that `org-babel-confirm-evaluate' is set locally by `let*'
to `org-ravel-no-confirm-for-ravel', which holds a `lambda'
function. To override this, create a variable with that name."
(org-ravel-export-wrapper
(let ((buffer (or buffer
(format "* %S Output *"
(org-export-backend-name backend)))))
(when async (user-error "ASYNC not allow for ravel"))
(org-ravel-reset-confirm org-ravel-no-confirm-for-ravel)
(org-export-to-buffer backend buffer async subtreep visible-only
body-only ext-plist post-process))))
;; defun-org-ravel-extension
;; #+NAME: defun-org-ravel-extension
(defun org-ravel-extension (style)
"Get the file extension for STYLE."
(nth 3 (assoc-string style org-ravel-style-alist)))
;; defmacro-ravel-define-exporter
;; #+NAME: defmacro-ravel-define-exporter
(defmacro org-ravel-define-exporter
(ravel-backend parent menu-key menu-label style-default
&optional fileout bufferout post-proc filters)
"Define ravel backends.
The arguments are:
RAVEL-BACKEND is a symbol naming the backend derived from
PARENT is a registered backend,
MENU-KEY should be an integer code for a lower-case
character like `?a' to refer to file dispatch,
MENU-LABEL tells how to label the backend in the
dispatch menu,
STYLE-DEFAULT is the style to use if not specified as a
`:ravel-style' attribute,
FILEOUT is usually nil which allows
`org-ravel-export-to-file' to assign the file name
BUFFEROUT is usually `t' - if non-nil create menu
entry `(upcase MENU-KEY)' that will be used for menu
dispatch) or nil for no buffer dispatcher, and
POST-PROC is a post-export hook function or nil
FILTERS is an alist of filters that will overwrite or
complete filters defined in PARENT back-end. See
`org-export-filters-alist' for a list of allowed filters."
`(org-export-define-derived-backend
,ravel-backend
,parent
:translate-alist '(
(export-snippet . org-ravel-export-snippet)
(export-block . org-ravel-export-block))
:options-alist '((:ravel-style "RAVEL_STYLE"
nil ,style-default t))
:filters-alist ,filters
:menu-entry
'(?r "Ravel"
,(remq nil
`((,menu-key ,(concat menu-label " file")
(lambda (a s v b)
(org-ravel-export-to-file
,ravel-backend ,fileout a s v b nil
nil nil ,style-default)))
,(if bufferout
`(,(upcase menu-key) ,(concat menu-label " buffer")
(lambda (a s v b)
(org-ravel-export-to-buffer
,ravel-backend nil a s v b nil ,post-proc
nil ,style-default)))))))))
;; Create Backends
;; The `(eval-after-load FILE FORM)' forms seems to work. i.e. FORM is
;; executed if the backend specified in FILE (e.g. 'ox-latex) is already loaded.
;; If not, then when FILE is loaded, FORM is run.
;; The variable `org-export-backends' can be customized to (de-)list
;; parent backends. The `ravel' backends that depend on those parents are
;; (de-)activated when the parent is (de-)listed.
;; A ravel backend whose parent is not in `org-export-backends' will need
;; to `require' or `load' that parent.
;; #+NAME: run-org-ravel-define-exporters
(eval-after-load 'ox-latex
'(org-ravel-define-exporter
'ravel-latex
'latex ?l "Ravel-LaTeX" "rnw" nil t (lambda () (LaTeX-mode))))
(eval-after-load 'ox-beamer
'(org-ravel-define-exporter
'ravel-beamer
'beamer ?b "Ravel-beamer" "rnw" nil t (lambda () (LaTeX-mode)))
)
(eval-after-load 'ox-html
'(org-ravel-define-exporter
'ravel-html
'html ?h "Ravel-html" "html" nil t ))
(defun org-ravel-filter-cite-as-pandoc (text back-end info)
"Translate citations in latex format (i.e. \cite{id}) into
citations in pandoc format (i.e. [@id]).
Note, loading `ox-bibtex' transforms all latex/bibtex citations
into html links, so do not load it if this format is desired."
(replace-regexp-in-string ",[\s-]*" "; @"
(replace-regexp-in-string
"\\\\cite{\\(.*\\)}" "[@\\1]" text)))
(eval-after-load 'ox-md
'(org-ravel-define-exporter
'ravel-markdown
'md ?m "Ravel-markdown" "md" nil t nil
'((:filter-latex-fragment . org-ravel-filter-cite-as-pandoc))))
;; provide ravel :noexport:
(provide 'ox-ravel)
;;; ox-ravel.el ends here