823 lines
30 KiB
EmacsLisp
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
|