summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Goaziou <n.goaziou@gmail.com>2011-11-28 23:36:51 +0100
committerNicolas Goaziou <n.goaziou@gmail.com>2011-11-28 23:38:25 +0100
commit0b51c3d6a9f2a758a7e49a6e9f333ea273f345bc (patch)
treeb6ac4f6a1c97bfbdfe03640b9de5710f0819870f
parent21758c30c90ab72ad243fb1ba2cb06eea88997b5 (diff)
downloadorg-mode-0b51c3d6a9f2a758a7e49a6e9f333ea273f345bc.tar.gz
EXPERIMENTAL/org-latex: LaTeX back-end for generic exporter
* EXPERIMENTAL/org-latex.el (org-latex-option-alist, org-latex-default-class, org-latex-classes org-latex-inputenc-alist, org-latex-date-format, org-latex-title-command, org-latex-format-headline-function, org-latex-emphasis-alist, org-latex-footnote-separator, org-latex-active-timestamp-format, org-latex-inactive-timestamp-format, org-latex-diary-timestamp-format, org-latex-image-default-option, org-latex-default-figure-position, org-latex-inline-image-extensions, org-latex-default-table-environment, org-latex-tables-centered, org-latex-tables-verbatim, org-latex-table-caption-above, org-latex-format-drawer-function, org-latex-format-inlinetask-function, org-latex-listings, org-latex-listings-langs, org-latex-listings-options, org-latex-minted-langs, org-latex-minted-options, org-latex-quotes, org-latex-custom-lang-environments): New variables. (org-latex--caption/label-string, org-latex--guess-inputenc, org-latex--find-verb-separator, org-latex--make-option-string, org-latex--quotation-marks, org-latex--wrap-label, org-latex-template, org-latex-center-block, org-latex-drawer, org-latex-dynamic-block, org-latex-emphasis, org-latex-entity, org-latex-example-block, org-latex-export-snippet, org-latex-export-block, org-latex-fixed-width, org-latex-footnote-reference, org-latex-headline, org-latex-horizontal-rule, org-latex-inline-src-block, org-latex-inlinetask, org-latex-item, org-latex-keyword, org-latex-latex-environment, org-latex-latex-fragment, org-latex-line-break, org-latex-link--inline-image, org-latex-link, org-latex-macro, org-latex-paragraph, org-latex-plain-list, org-latex-plain-text, org-latex-property-drawer, org-latex-quote-block, org-latex-quote-section, org-latex-radio-target, org-latex-special-block, org-latex-src-block, org-latex-statistics-cookie, org-latex-subscript, org-latex-superscript, org-latex-table--format-string, org-latex-table--align-string, org-latex-table, org-latex-target, org-latex-time-stamp, org-latex-verbatim, org-latex-verse-block): New functions.
-rw-r--r--EXPERIMENTAL/org-latex.el1839
1 files changed, 1839 insertions, 0 deletions
diff --git a/EXPERIMENTAL/org-latex.el b/EXPERIMENTAL/org-latex.el
new file mode 100644
index 0000000..47f7c29
--- /dev/null
+++ b/EXPERIMENTAL/org-latex.el
@@ -0,0 +1,1839 @@
+;;; org-latex.el --- LaTeX Back-End For Org Export Engine
+
+;; Copyright (C) 2011 Free Software Foundation, Inc.
+
+;; Author: Nicolas Goaziou <n.goaziou at gmail dot com>
+;; Keywords: outlines, hypermedia, calendar, wp
+
+;; 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:
+
+;; This library implements a LaTeX back-end for Org generic exporter.
+
+;; It introduces three new buffer keywords: "LATEX_CLASS",
+;; "LATEX_CLASS_OPTIONS" and "LATEX_HEADER".
+
+;;; Code:
+
+(eval-when-compile (require 'cl))
+(require 'org-element)
+(require 'org-export)
+
+
+
+;;; Internal Variables
+
+(defconst org-latex-option-alist
+ '((:date "DATE" nil org-latex-date-format t)
+ (:latex-class "LATEX_CLASS" nil org-latex-default-class t)
+ (:latex-class-options "LATEX_CLASS_OPTIONS" nil nil t)
+ (:latex-header-extra "LATEX_HEADER" nil nil newline))
+ "Alist between LaTeX export properties and ways to set them.
+See `org-export-option-alist' for more information on the
+structure of the value.")
+
+
+
+;;; User Configurable Variables
+
+(defgroup org-export-latex nil
+ "Options for exporting Org mode files to LaTeX."
+ :tag "Org Export LaTeX"
+ :group 'org-export)
+
+
+;;;; Preamble
+
+(defcustom org-latex-default-class "article"
+ "The default LaTeX class."
+ :group 'org-export-latex
+ :type '(string :tag "LaTeX class"))
+
+(defcustom org-latex-classes
+ '(("article"
+ "\\documentclass[11pt]{article}"
+ ("\\section{%s}" . "\\section*{%s}")
+ ("\\subsection{%s}" . "\\subsection*{%s}")
+ ("\\subsubsection{%s}" . "\\subsubsection*{%s}")
+ ("\\paragraph{%s}" . "\\paragraph*{%s}")
+ ("\\subparagraph{%s}" . "\\subparagraph*{%s}"))
+ ("report"
+ "\\documentclass[11pt]{report}"
+ ("\\part{%s}" . "\\part*{%s}")
+ ("\\chapter{%s}" . "\\chapter*{%s}")
+ ("\\section{%s}" . "\\section*{%s}")
+ ("\\subsection{%s}" . "\\subsection*{%s}")
+ ("\\subsubsection{%s}" . "\\subsubsection*{%s}"))
+ ("book"
+ "\\documentclass[11pt]{book}"
+ ("\\part{%s}" . "\\part*{%s}")
+ ("\\chapter{%s}" . "\\chapter*{%s}")
+ ("\\section{%s}" . "\\section*{%s}")
+ ("\\subsection{%s}" . "\\subsection*{%s}")
+ ("\\subsubsection{%s}" . "\\subsubsection*{%s}")))
+ "Alist of LaTeX classes and associated header and structure.
+If #+LaTeX_CLASS is set in the buffer, use its value and the
+associated information. Here is the structure of each cell:
+
+ \(class-name
+ header-string
+ \(numbered-section . unnumbered-section\)
+ ...\)
+
+The header string
+-----------------
+
+The HEADER-STRING is the header that will be inserted into the LaTeX file.
+It should contain the \\documentclass macro, and anything else that is needed
+for this setup. To this header, the following commands will be added:
+
+- Calls to \\usepackage for all packages mentioned in the variables
+ `org-latex-default-packages-alist' and
+ `org-latex-packages-alist'. Thus, your header definitions should
+ avoid to also request these packages.
+
+- Lines specified via \"#+LaTeX_HEADER:\"
+
+If you need more control about the sequence in which the header is built
+up, or if you want to exclude one of these building blocks for a particular
+class, you can use the following macro-like placeholders.
+
+ [DEFAULT-PACKAGES] \\usepackage statements for default packages
+ [NO-DEFAULT-PACKAGES] do not include any of the default packages
+ [PACKAGES] \\usepackage statements for packages
+ [NO-PACKAGES] do not include the packages
+ [EXTRA] the stuff from #+LaTeX_HEADER
+ [NO-EXTRA] do not include #+LaTeX_HEADER stuff
+ [BEAMER-HEADER-EXTRA] the beamer extra headers
+
+So a header like
+
+ \\documentclass{article}
+ [NO-DEFAULT-PACKAGES]
+ [EXTRA]
+ \\providecommand{\\alert}[1]{\\textbf{#1}}
+ [PACKAGES]
+
+will omit the default packages, and will include the #+LaTeX_HEADER lines,
+then have a call to \\providecommand, and then place \\usepackage commands
+based on the content of `org-latex-packages-alist'.
+
+If your header or `org-latex-default-packages-alist' inserts
+\"\\usepackage[AUTO]{inputenc}\", AUTO will automatically be replaced with
+a coding system derived from `buffer-file-coding-system'. See also the
+variable `org-latex-inputenc-alist' for a way to influence this
+mechanism.
+
+The sectioning structure
+------------------------
+
+The sectioning structure of the class is given by the elements following
+the header string. For each sectioning level, a number of strings is
+specified. A %s formatter is mandatory in each section string and will
+be replaced by the title of the section.
+
+Instead of a cons cell \(numbered . unnumbered\), you can also
+provide a list of 2 or 4 elements,
+
+ \(numbered-open numbered-close\)
+
+or
+
+ \(numbered-open numbered-close unnumbered-open unnumbered-close\)
+
+providing opening and closing strings for a LaTeX environment that should
+represent the document section. The opening clause should have a %s
+to represent the section title.
+
+Instead of a list of sectioning commands, you can also specify a
+function name. That function will be called with two parameters,
+the (reduced) level of the headline, and a predicate non-nil when
+the headline should be numbered. It must return a format string in
+which the section title will be added."
+ :group 'org-export-latex
+ :type '(repeat
+ (list (string :tag "LaTeX class")
+ (string :tag "LaTeX header")
+ (repeat :tag "Levels" :inline t
+ (choice
+ (cons :tag "Heading"
+ (string :tag " numbered")
+ (string :tag "unnumbered"))
+ (list :tag "Environment"
+ (string :tag "Opening (numbered)")
+ (string :tag "Closing (numbered)")
+ (string :tag "Opening (unnumbered)")
+ (string :tag "Closing (unnumbered)"))
+ (function :tag "Hook computing sectioning"))))))
+
+(defcustom org-latex-inputenc-alist nil
+ "Alist of inputenc coding system names, and what should really be used.
+For example, adding an entry
+
+ (\"utf8\" . \"utf8x\")
+
+will cause \\usepackage[utf8x]{inputenc} to be used for buffers that
+are written as utf8 files."
+ :group 'org-export-latex
+ :type '(repeat
+ (cons
+ (string :tag "Derived from buffer")
+ (string :tag "Use this instead"))))
+
+(defcustom org-latex-date-format
+ "\\today"
+ "Format string for \\date{...}."
+ :group 'org-export-latex
+ :type 'boolean)
+
+(defcustom org-latex-title-command "\\maketitle"
+ "The command used to insert the title just after \\begin{document}.
+If this string contains the formatting specification \"%s\" then
+it will be used as a formatting string, passing the title as an
+argument."
+ :group 'org-export-latex
+ :type 'string)
+
+
+;;;; Headline
+
+(defcustom org-latex-format-headline-function nil
+ "Function to format headline text.
+
+This function will be called with 5 arguments:
+TODO the todo keyword \(string or nil\).
+TODO-TYPE the type of todo \(symbol: `todo', `done', nil\)
+PRIORITY the priority of the headline \(integer or nil\)
+TEXT the main headline text \(string\).
+TAGS the tags string, separated with colons \(string or nil\).
+
+The function result will be used in the section format string.
+
+As an example, one could set the variable to the following, in
+order to reproduce the default set-up:
+
+\(defun org-latex-format-headline-default \(todo todo-type priority text tags\)
+ \"Default format function for an headline.\"
+ \(concat \(when todo \(format \"\\\\textbf{\\\\textsc{\\\\textsf{%s}}} \" todo\)\)
+ \(when priority \(format \"\\\\framebox{\\\\#%c} \" priority\)\)
+ text
+ \(when tags \(format \"\\\\hfill{}\\\\textsc{%s}\" tags\)\)\)\)"
+ :group 'org-export-latex
+ :type 'function)
+
+
+;;;; Emphasis
+
+(defcustom org-latex-emphasis-alist
+ '(("*" . "\\textbf{%s}")
+ ("/" . "\\emph{%s}")
+ ("_" . "\\underline{%s}")
+ ("+" . "\\st{%s}")
+ ("=" . protectedtexttt)
+ ("~" . verb))
+ "Alist of LaTeX expressions to convert emphasis fontifiers.
+
+The key is the character used as a marker for fontification. The
+value is a formatting string to wrap fontified text with.
+
+Value can also be set to the following symbols: `verb' and
+`protectedtexttt'. For the former, Org will use \"\\verb\" to
+create a format string and select a delimiter character that
+isn't in the string. For the latter, Org will use \"\\texttt\"
+to typeset and try to protect special characters."
+ :group 'org-export-latex
+ :type 'alist)
+
+
+;;;; Footnotes
+
+(defcustom org-latex-footnote-separator "\\textsuperscript{,}\\,"
+ "Text used to separate footnotes."
+ :group 'org-export-latex
+ :type 'string)
+
+
+;;;; Time-stamps
+
+(defcustom org-latex-active-timestamp-format "\\textit{%s}"
+ "A printf format string to be applied to active time-stamps."
+ :group 'org-export-latex
+ :type 'string)
+
+(defcustom org-latex-inactive-timestamp-format "\\textit{%s}"
+ "A printf format string to be applied to inactive time-stamps."
+ :group 'org-export-latex
+ :type 'string)
+
+(defcustom org-latex-diary-timestamp-format "\\textit{%s}"
+ "A printf format string to be applied to diary time-stamps."
+ :group 'org-export-latex
+ :type 'string)
+
+
+;;;; Links
+
+(defcustom org-latex-image-default-option "width=.9\\linewidth"
+ "Default option for images."
+ :group 'org-export-latex
+ :type 'string)
+
+(defcustom org-latex-default-figure-position "htb"
+ "Default position for latex figures."
+ :group 'org-export-latex
+ :type 'string)
+
+(defcustom org-latex-inline-image-extensions
+ '("pdf" "jpeg" "jpg" "png" "ps" "eps")
+ "Extensions of image files that can be inlined into LaTeX.
+
+Note that the image extension *actually* allowed depend on the
+way the LaTeX file is processed. When used with pdflatex, pdf,
+jpg and png images are OK. When processing through dvi to
+Postscript, only ps and eps are allowed. The default we use here
+encompasses both."
+ :group 'org-export-latex
+ :type '(repeat (string :tag "Extension")))
+
+
+;;;; Tables
+
+(defcustom org-latex-default-table-environment "tabular"
+ "Default environment used to build tables."
+ :group 'org-export-latex
+ :type 'string)
+
+(defcustom org-latex-tables-centered t
+ "When non-nil, tables are exported in a center environment."
+ :group 'org-export-latex
+ :type 'boolean)
+
+(defcustom org-latex-tables-verbatim nil
+ "When non-nil, tables are exported verbatim."
+ :group 'org-export-latex
+ :type 'boolean)
+
+(defcustom org-latex-table-caption-above t
+ "When non-nil, place caption string at the beginning of the table.
+Otherwise, place it near the end."
+ :group 'org-export-latex
+ :type 'boolean)
+
+
+;;;; Drawers
+
+(defcustom org-latex-format-drawer-function nil
+ "Function called to format a drawer in LaTeX code.
+
+The function must accept two parameters:
+ NAME the drawer name, like \"LOGBOOK\"
+ CONTENTS the contents of the drawer.
+
+The function should return the string to be exported.
+
+For example, the variable could be set to the following function
+in order to mimic default behaviour:
+
+\(defun org-latex-format-drawer-default \(name contents\)
+ \"Format a drawer element for LaTeX export.\"
+ contents\)"
+ :group 'org-export-latex
+ :type 'function)
+
+
+;;;; Inlinetasks
+
+(defcustom org-latex-format-inlinetask-function nil
+ "Function called to format an inlinetask in LaTeX code.
+
+The function must accept six parameters:
+ TODO the todo keyword, as a string
+ TODO-TYPE the todo type, a symbol among `todo', `done' and nil.
+ PRIORITY the inlinetask priority, as a string
+ NAME the inlinetask name, as a string.
+ TAGS the inlinetask tags, as a string.
+ CONTENTS the contents of the inlinetask, as a string.
+
+The function should return the string to be exported.
+
+For example, the variable could be set to the following function
+in order to mimic default behaviour:
+
+\(defun org-latex-format-inlinetask-default \(todo type priority name tags contents\)
+\"Format an inline task element for LaTeX export.\"
+ \(let \(\(full-title
+ \(concat
+ \(when todo \(format \"\\\\textbf{\\\\textsf{\\\\textsc{%s}}} \" todo\)\)
+ \(when priority \(format \"\\\\framebox{\\\\#%c} \" priority\)\)
+ title
+ \(when tags \(format \"\\\\hfill{}\\\\textsc{%s}\" tags\)\)\)\)\)
+ \(format \(concat \"\\\\begin{center}\\n\"
+ \"\\\\fbox{\\n\"
+ \"\\\\begin{minipage}[c]{.6\\\\textwidth}\\n\"
+ \"%s\\n\\n\"
+ \"\\\\rule[.8em]{\\\\textwidth}{2pt}\\n\\n\"
+ \"%s\"
+ \"\\\\end{minipage}}\"
+ \"\\\\end{center}\"\)
+ full-title contents\)\)"
+ :group 'org-export-latex
+ :type 'function)
+
+
+;; Src blocks
+
+(defcustom org-latex-listings nil
+ "Non-nil means export source code using the listings package.
+This package will fontify source code, possibly even with color.
+If you want to use this, you also need to make LaTeX use the
+listings package, and if you want to have color, the color
+package. Just add these to `org-latex-packages-alist',
+for example using customize, or with something like
+
+ (require 'org-latex)
+ (add-to-list 'org-export-latex-packages-alist '(\"\" \"listings\"))
+ (add-to-list 'org-export-latex-packages-alist '(\"\" \"color\"))
+
+Alternatively,
+
+ (setq org-latex-listings 'minted)
+
+causes source code to be exported using the minted package as
+opposed to listings. If you want to use minted, you need to add
+the minted package to `org-latex-packages-alist', for
+example using customize, or with
+
+ (require 'org-latex)
+ (add-to-list 'org-latex-packages-alist '(\"\" \"minted\"))
+
+In addition, it is necessary to install
+pygments (http://pygments.org), and to configure the variable
+`org-latex-to-pdf-process' so that the -shell-escape option is
+passed to pdflatex."
+ :group 'org-export-latex
+ :type '(choice
+ (const :tag "Use listings" t)
+ (const :tag "Use minted" 'minted)
+ (const :tag "Export verbatim" nil)))
+
+(defcustom org-latex-listings-langs
+ '((emacs-lisp "Lisp") (lisp "Lisp") (clojure "Lisp")
+ (c "C") (cc "C++")
+ (fortran "fortran")
+ (perl "Perl") (cperl "Perl") (python "Python") (ruby "Ruby")
+ (html "HTML") (xml "XML")
+ (tex "TeX") (latex "TeX")
+ (shell-script "bash")
+ (gnuplot "Gnuplot")
+ (ocaml "Caml") (caml "Caml")
+ (sql "SQL") (sqlite "sql"))
+ "Alist mapping languages to their listing language counterpart.
+The key is a symbol, the major mode symbol without the \"-mode\".
+The value is the string that should be inserted as the language parameter
+for the listings package. If the mode name and the listings name are
+the same, the language does not need an entry in this list - but it does not
+hurt if it is present."
+ :group 'org-export-latex
+ :type '(repeat
+ (list
+ (symbol :tag "Major mode ")
+ (string :tag "Listings language"))))
+
+(defcustom org-latex-listings-options nil
+ "Association list of options for the latex listings package.
+
+These options are supplied as a comma-separated list to the
+\\lstset command. Each element of the association list should be
+a list containing two strings: the name of the option, and the
+value. For example,
+
+ (setq org-export-latex-listings-options
+ '((\"basicstyle\" \"\\small\")
+ (\"keywordstyle\" \"\\color{black}\\bfseries\\underbar\")))
+
+will typeset the code in a small size font with underlined, bold
+black keywords.
+
+Note that the same options will be applied to blocks of all
+languages."
+ :group 'org-export-latex
+ :type '(repeat
+ (list
+ (string :tag "Listings option name ")
+ (string :tag "Listings option value"))))
+
+(defcustom org-latex-minted-langs
+ '((emacs-lisp "common-lisp")
+ (cc "c++")
+ (cperl "perl")
+ (shell-script "bash")
+ (caml "ocaml"))
+ "Alist mapping languages to their minted language counterpart.
+The key is a symbol, the major mode symbol without the \"-mode\".
+The value is the string that should be inserted as the language parameter
+for the minted package. If the mode name and the listings name are
+the same, the language does not need an entry in this list - but it does not
+hurt if it is present.
+
+Note that minted uses all lower case for language identifiers,
+and that the full list of language identifiers can be obtained
+with:
+pygmentize -L lexers"
+ :group 'org-export-latex
+ :type '(repeat
+ (list
+ (symbol :tag "Major mode ")
+ (string :tag "Minted language"))))
+
+(defcustom org-latex-minted-options nil
+ "Association list of options for the latex minted package.
+
+These options are supplied within square brackets in
+\\begin{minted} environments. Each element of the alist should be
+a list containing two strings: the name of the option, and the
+value. For example,
+
+ (setq org-export-latex-minted-options
+ '((\"bgcolor\" \"bg\") (\"frame\" \"lines\")))
+
+will result in src blocks being exported with
+
+\\begin{minted}[bgcolor=bg,frame=lines]{<LANG>}
+
+as the start of the minted environment. Note that the same
+options will be applied to blocks of all languages."
+ :group 'org-export-latex
+ :type '(repeat
+ (list
+ (string :tag "Minted option name ")
+ (string :tag "Minted option value"))))
+
+(defvar org-latex-custom-lang-environments nil
+ "Association list mapping languages to language-specific latex
+environments used during export of src blocks by the listings and
+minted latex packages. For example,
+
+ (setq org-export-latex-custom-lang-environments
+ '((python \"pythoncode\")))
+
+would have the effect that if org encounters begin_src python
+during latex export it will output
+
+ \\begin{pythoncode}
+ <src block body>
+ \\end{pythoncode}")
+
+
+;;;; Plain text
+
+(defcustom org-latex-quotes
+ '(("fr" ("\\(\\s-\\|[[(]\\)\"" . "«~") ("\\(\\S-\\)\"" . "~»") ("\\(\\s-\\|(\\)'" . "'"))
+ ("en" ("\\(\\s-\\|[[(]\\)\"" . "``") ("\\(\\S-\\)\"" . "''") ("\\(\\s-\\|(\\)'" . "`")))
+ "Alist for quotes to use when converting english double-quotes.
+
+The CAR of each item in this alist is the language code.
+The CDR of each item in this alist is a list of three CONS:
+- the first CONS defines the opening quote;
+- the second CONS defines the closing quote;
+- the last CONS defines single quotes.
+
+For each item in a CONS, the first string is a regexp
+for allowed characters before/after the quote, the second
+string defines the replacement string for this quote."
+ :group 'org-export-latex
+ :type '(list
+ (cons :tag "Opening quote"
+ (string :tag "Regexp for char before")
+ (string :tag "Replacement quote "))
+ (cons :tag "Closing quote"
+ (string :tag "Regexp for char after ")
+ (string :tag "Replacement quote "))
+ (cons :tag "Single quote"
+ (string :tag "Regexp for char before")
+ (string :tag "Replacement quote "))))
+
+
+
+;;; Internal Functions
+
+(defun org-latex--caption/label-string (caption label info)
+ "Return caption and label LaTeX string for floats.
+
+CAPTION is a secondary string \(a list of strings and Org
+objects\) and LABEL a string representing the label. INFO is
+a plist holding contextual information.
+
+If there's no caption nor label, return the empty string.
+
+For non-floats, see `org-latex--wrap-label'."
+ (let ((caption-str (and caption
+ (org-export-secondary-string
+ caption 'latex info)))
+ (label-str (if label (format "\\label{%s}" label) "")))
+ (cond
+ ((and (not caption-str) (not label)) "")
+ ((not caption-str) (format "\\label{%s}\n" label))
+ ;; Option caption format with short name.
+ ((string-match "\\[\\([^][]*\\)\\]{\\([^{}]*\\)}" caption-str)
+ (format "\\caption[%s]{%s%s}\n"
+ (org-match-string-no-properties 1 caption-str)
+ label-str
+ (org-match-string-no-properties 2 caption-str)))
+ ;; Standard caption format.
+ (t (format "\\caption{%s%s}\n" label-str caption-str)))))
+
+(defun org-latex--guess-inputenc (header)
+ "Set the coding system in inputenc to what the buffer is.
+
+HEADER is the LaTeX header string.
+
+Return the new header."
+ (let* ((cs (or (ignore-errors
+ (latexenc-coding-system-to-inputenc
+ buffer-file-coding-system))
+ "utf8")))
+ (if (not cs)
+ header
+ ;; First translate if that is requested.
+ (setq cs (or (cdr (assoc cs org-latex-inputenc-alist)) cs))
+ ;; Then find the \usepackage statement and replace the option.
+ (replace-regexp-in-string "\\\\usepackage\\[\\(AUTO\\)\\]{inputenc}"
+ cs header t nil 1))))
+
+(defun org-latex--find-verb-separator (s)
+ "Return a character not used in string S.
+This is used to choose a separator for constructs like \\verb."
+ (let ((ll "~,./?;':\"|!@#%^&-_=+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ<>()[]{}"))
+ (loop for c across ll
+ when (not (string-match (regexp-quote (char-to-string c)) s))
+ return (char-to-string c))))
+
+(defun org-latex--make-option-string (options)
+ "Return a comma separated string of keywords and values.
+OPTIONS is an alist where the key is the options keyword as
+a string, and the value a list containing the keyword value, or
+nil."
+ (mapconcat (lambda (pair)
+ (concat (first pair)
+ (when (> (length (second pair)) 0)
+ (concat "=" (second pair)))))
+ options
+ ","))
+
+(defun org-latex--quotation-marks (text info)
+ "Export quotation marks depending on language conventions."
+ (mapc (lambda(l)
+ (let ((start 0))
+ (while (setq start (string-match (car l) text start))
+ (let ((new-quote (concat (match-string 1 text) (cdr l))))
+ (setq text (replace-match new-quote t t text))))))
+ (cdr (or (assoc (plist-get info :language) org-latex-quotes)
+ ;; Falls back on English.
+ (assoc "en" org-latex-quotes))))
+ text)
+
+(defun org-latex--wrap-label (element output)
+ "Wrap label associated to ELEMENT around OUTPUT, if appropriate.
+This function shouldn't be used for floats. See
+`org-latex--caption/label-string'."
+ (let ((label (org-element-get-property :name element)))
+ (if (or (not output) (not label) (string= output "") (string= label ""))
+ output
+ (concat (format "\\label{%s}\n" label) output))))
+
+
+
+;;; Template
+
+(defun org-latex-template (contents info)
+ "Return complete document string after LaTeX conversion.
+CONTENTS is the transcoded contents string. INFO is a plist
+holding export options."
+ (let ((title (org-export-secondary-string
+ (plist-get info :title) 'latex info)))
+ (concat
+ ;; 1. Time-stamp.
+ (and (plist-get info :time-stamp-file)
+ (format-time-string "%% Created %Y-%m-%d %a %H:%M\n"))
+ ;; 2. Document class and packages.
+ (let ((class (plist-get info :latex-class))
+ (class-options (plist-get info :latex-class-options)))
+ (org-element-normalize-string
+ (let* ((header (nth 1 (assoc class org-latex-classes)))
+ (document-class-string
+ (and (stringp header)
+ (if class-options
+ (replace-regexp-in-string
+ "^[ \t]*\\\\documentclass\\(\\[.*?\\]\\)"
+ class-options header t nil 1)
+ header))))
+ (org-latex--guess-inputenc
+ (org-splice-latex-header
+ document-class-string
+ org-export-latex-default-packages-alist ; defined in org.el
+ org-export-latex-packages-alist nil ; defined in org.el
+ (plist-get info :latex-header-extra))))))
+ ;; 3. Define alert if not yet defined.
+ "\\providecommand{\\alert}[1]{\\textbf{#1}}\n"
+ ;; 4. Author.
+ (let ((author (and (plist-get info :with-author)
+ (let ((auth (plist-get info :author)))
+ (and auth (org-export-secondary-string
+ auth 'latex info)))))
+ (email (and (plist-get info :with-email)
+ (org-export-secondary-string
+ (plist-get info :email) 'latex info))))
+ (cond ((and author email (not (string= "" email)))
+ (format "\\author{%s\\thanks{%s}}\n" author email))
+ (author (format "\\author{%s}\n" author))
+ (t "\\author{}\n")))
+ ;; 5. Date.
+ (let ((date (plist-get info :date)))
+ (and date (format "\\date{%s}\n" date)))
+ ;; 6. Title
+ (format "\\title{%s}\n" title)
+ ;; 7. Hyperref options.
+ (format "\\hypersetup{\n pdfkeywords={%s},\n pdfsubject={%s},\n pdfcreator={%s}}\n"
+ (or (plist-get info :keywords) "")
+ (or (plist-get info :description) "")
+ (let ((creator-info (plist-get info :with-creator)))
+ (cond
+ ((not creator-info) "")
+ ((eq creator-info 'comment) "")
+ (t (plist-get info :creator)))))
+ ;; 7. Document start.
+ "\\begin{document}\n\n"
+ ;; 8. Title command.
+ (org-element-normalize-string
+ (cond ((string= "" title) nil)
+ ((not (stringp org-latex-title-command)) nil)
+ ((string-match "\\(?:[^%]\\|^\\)%s"
+ org-latex-title-command)
+ (format org-latex-title-command title))
+ (t org-latex-title-command)))
+ ;; 9. Table of contents.
+ (let ((depth (plist-get info :with-toc)))
+ (when depth
+ (concat (when (wholenump depth)
+ (format "\\setcounter{tocdepth}{%d}\n" depth))
+ "\\tableofcontents\n\\vspace*{1cm}\n\n")))
+ ;; 10. Document's body.
+ contents
+ ;; 11. Creator.
+ (let ((creator-info (plist-get info :with-creator)))
+ (cond
+ ((not creator-info))
+ ((eq creator-info 'comment)
+ (format "%% %s\n" (plist-get info :creator)))
+ (t (concat (plist-get info :creator) "\n"))))
+ ;; 12. Document end.
+ "\\end{document}")))
+
+
+
+;;; Transcode Functions
+
+;;;; Block
+
+(defun org-latex-center-block (center-block contents info)
+ "Transcode a CENTER-BLOCK element from Org to LaTeX.
+CONTENTS holds the contents of the block. INFO is a plist
+holding contextual information."
+ (org-latex--wrap-label
+ center-block
+ (format "\\begin{center}\n%s\\end{center}" contents)))
+
+
+;;;; Comment
+
+;; Comments are ignored.
+
+
+;;;; Comment Block
+
+;; Comment Blocks are ignored.
+
+
+;;;; Drawer
+
+(defun org-latex-drawer (drawer contents info)
+ "Transcode a DRAWER element from Org to LaTeX.
+CONTENTS holds the contents of the block. INFO is a plist
+holding contextual information."
+ (let* ((name (org-element-get-property :drawer-name drawer))
+ (output (if (functionp org-latex-format-drawer-function)
+ (funcall org-latex-format-drawer-function
+ name contents)
+ ;; If there's no user defined function: simply
+ ;; display contents of the drawer.
+ contents)))
+ (org-latex--wrap-label drawer output)))
+
+
+;;;; Dynamic Block
+
+(defun org-latex-dynamic-block (dynamic-block contents info)
+ "Transcode a DYNAMIC-BLOCK element from Org to LaTeX.
+CONTENTS holds the contents of the block. INFO is a plist
+holding contextual information. See
+`org-export-data'."
+ (org-latex--wrap-label dynamic-block contents))
+
+
+;;;; Emphasis
+
+(defun org-latex-emphasis (emphasis contents info)
+ "Transcode EMPHASIS from Org to LaTeX.
+CONTENTS is the contents of the emphasized text. INFO is a plist
+holding contextual information.."
+ (format (cdr (assoc (org-element-get-property :marker emphasis)
+ org-latex-emphasis-alist))
+ contents))
+
+
+;;;; Entity
+
+(defun org-latex-entity (entity contents info)
+ "Transcode an ENTITY object from Org to LaTeX.
+CONTENTS are the definition itself. INFO is a plist holding
+contextual information."
+ (let ((ent (org-element-get-property :latex entity)))
+ (if (org-element-get-property :latex-math-p entity)
+ (format "$%s$" ent)
+ ent)))
+
+
+;;;; Example Block
+
+(defun org-latex-example-block (example-block contents info)
+ "Transcode a EXAMPLE-BLOCK element from Org to LaTeX.
+CONTENTS is nil. INFO is a plist holding contextual information."
+ (let* ((options (or (org-element-get-property :options example-block) ""))
+ (value (org-export-handle-code
+ (org-element-get-property :value example-block) options info)))
+ (org-latex--wrap-label example-block value)))
+
+
+;;;; Export Snippet
+
+(defun org-latex-export-snippet (export-snippet contents info)
+ "Transcode a EXPORT-SNIPPET object from Org to LaTeX.
+CONTENTS is nil. INFO is a plist holding contextual information."
+ (org-element-get-property :value export-snippet))
+
+
+;;;; Export Block
+
+(defun org-latex-export-block (export-block contents info)
+ "Transcode a EXPORT-BLOCK element from Org to LaTeX.
+CONTENTS is nil. INFO is a plist holding contextual information."
+ (when (string= (org-element-get-property :type export-block) "latex")
+ (org-remove-indentation (org-element-get-property :value export-block))))
+
+
+;;;; Fixed Width
+
+(defun org-latex-fixed-width (fixed-width contents info)
+ "Transcode a FIXED-WIDTH element from Org to LaTeX.
+CONTENTS is nil. INFO is a plist holding contextual information."
+ (let* ((value (org-element-normalize-string
+ (replace-regexp-in-string
+ "^[ \t]*: ?" ""
+ (org-element-get-property :value fixed-width)))))
+ (org-latex--wrap-label
+ fixed-width
+ (format "\\begin{verbatim}\n%s\\end{verbatim}" value))))
+
+
+;;;; Footnote Definition
+
+;; Footnote Definitions are ignored.
+
+
+;;;; Footnote Reference
+
+(defun org-latex-footnote-reference (footnote-reference contents info)
+ "Transcode a FOOTNOTE-REFERENCE element from Org to LaTeX.
+CONTENTS is nil. INFO is a plist holding contextual information."
+ (concat
+ ;; Insert separator between two footnotes in a row.
+ (when (eq (plist-get info :previous-object) 'footnote-reference)
+ org-latex-footnote-separator)
+ ;; Use \footnotemark if the footnote has already been defined.
+ ;; Otherwise, define it with \footnote command.
+ (let* ((all-seen (plist-get org-export-persistent-properties
+ :seen-footnote-labels))
+ (label (org-element-get-property :label footnote-reference))
+ ;; Anonymous footnotes are always new footnotes.
+ (seenp (and label (member label all-seen)))
+ (inline-def-p (org-element-get-property
+ :inline-definition footnote-reference)))
+ (cond
+ (seenp (format "\\footnotemark[%s]" (length seenp)))
+ ;; Inline definitions are secondary strings.
+ (inline-def-p
+ (format "\\footnote{%s}"
+ (org-trim
+ (org-export-secondary-string inline-def-p 'latex info))))
+ ;; Non-inline footnotes necessarily contain a label. Retrieve
+ ;; match definition in `:footnotes-labels-alist'.
+ (t
+ (format "\\footnote{%s}"
+ (org-trim
+ (org-export-data
+ (cdr (assoc label (plist-get info :footnotes-labels-alist)))
+ 'latex info))))))))
+
+
+;;;; Headline
+
+(defun org-latex-headline (headline contents info)
+ "Transcode an HEADLINE element from Org to LaTeX.
+CONTENTS holds the contents of the headline. INFO is a plist
+holding contextual information."
+ (let* ((class (plist-get info :latex-class))
+ (numberedp (plist-get info :section-numbers))
+ ;; Get level relative to current parsed data.
+ (level (+ (org-element-get-property :level headline)
+ (plist-get info :headline-offset)))
+ (class-sectionning (assoc class org-latex-classes))
+ ;; Section formatting will set two placeholders: one for the
+ ;; title and the other for the contents.
+ (section-fmt
+ (let ((sec (if (and (symbolp (nth 2 class-sectionning))
+ (fboundp (nth 2 class-sectionning)))
+ (funcall (nth 2 class-sectionning) level numberedp)
+ (nth (1+ level) class-sectionning))))
+ (cond
+ ;; No section available for that LEVEL.
+ ((not sec) nil)
+ ;; Section format directly returned by a function.
+ ((stringp sec) sec)
+ ;; (numbered-section . unnumbered-section)
+ ((not (consp (cdr sec)))
+ (concat (funcall (if numberedp #'car #'cdr) sec) "\n%s"))
+ ;; (numbered-open numbered-close)
+ ((= (length sec) 2)
+ (when numberedp (concat (car sec) "\n%s" (nth 1 sec))))
+ ;; (num-in num-out no-num-in no-num-out)
+ ((= (length sec) 4)
+ (if numberedp
+ (concat (car sec) "\n%s" (nth 1 sec))
+ (concat (nth 2 sec) "\n%s" (nth 3 sec)))))))
+ (text (org-export-secondary-string
+ (org-element-get-property :title headline) 'latex info))
+ (todo (and (plist-get info :with-todo-keywords)
+ (let ((todo (org-element-get-property
+ :todo-keyword headline)))
+ (and todo
+ (org-export-secondary-string todo 'latex info)))))
+ (todo-type (and todo (org-element-get-property :todo-type headline)))
+ (tags (and (plist-get info :with-tags)
+ (org-element-get-property :tags headline)))
+ (priority (and (plist-get info :with-priority)
+ (org-element-get-property :priority headline)))
+ ;; Create the headline text.
+ (full-text (if (functionp org-latex-format-headline-function)
+ ;; User-defined formatting function.
+ (funcall org-latex-format-headline-function
+ todo todo-type priority text tags)
+ ;; Default formatting.
+ (concat
+ (when todo
+ (format "\\textbf{\\textsf{\\textsc{%s}}} " todo))
+ (when priority (format "\\framebox{\\#%c} " priority))
+ text
+ (when tags (format "\\hfill{}\\textsc{%s}" tags)))))
+ ;; Associate some \label to the headline for internal links.
+ (headline-labels (mapconcat
+ (lambda (p)
+ (let ((val (org-element-get-property p headline)))
+ (when val (format "\\label{%s}\n"
+ (if (eq p :begin)
+ (format "headline-%s" val)
+ val)))))
+ '(:custom-id :id :begin) ""))
+ (pre-blanks (make-string (org-element-get-property :pre-blank headline)
+ 10)))
+ (cond
+ ;; Case 1: This is a footnote section: ignore it.
+ ((org-element-get-property :footnote-section-p headline) nil)
+ ;; Case 2. This is a deep sub-tree: export it as a list item.
+ ;; Also export as items headlines for which no section
+ ;; format has been found.
+ ((or (not section-fmt)
+ (and (wholenump (plist-get info :headline-levels))
+ (> level (plist-get info :headline-levels))))
+ ;; Build the real contents of the sub-tree.
+ (let ((low-level-body
+ (concat
+ ;; If the headline is the first sibling, start a list.
+ (when (org-export-first-sibling-p headline info)
+ (format "\\begin{%s}\n" (if numberedp 'enumerate 'itemize)))
+ ;; Itemize headline
+ "\\item " full-text "\n" headline-labels pre-blanks contents)))
+ ;; If headline in the last sibling, close the list, before any
+ ;; blank line. Otherwise, simply return LOW-LEVEL-BODY.
+ (if (org-export-last-sibling-p headline info)
+ (replace-regexp-in-string
+ "[ \t\n]*\\'"
+ (format "\n\\\\end{%s}" (if numberedp 'enumerate 'itemize))
+ low-level-body)
+ low-level-body)))
+ ;; Case 3. Standard headline. Export it as a section.
+ (t (format section-fmt full-text
+ (concat headline-labels pre-blanks contents))))))
+
+
+;;;; Horizontal Rule
+
+(defun org-latex-horizontal-rule (horizontal-rule contents info)
+ "Transcode an HORIZONTAL-RULE object from Org to LaTeX.
+CONTENTS is nil. INFO is a plist holding contextual information."
+ (let ((attr (mapconcat #'identity
+ (org-element-get-property :attr_latex horizontal-rule)
+ " ")))
+ (org-latex--wrap-label horizontal-rule (concat "\\hrule " attr))))
+
+
+;;;; Inline Babel Call
+
+;; Inline Babel Calls are ignored.
+
+
+;;;; Inline Src Block
+
+(defun org-latex-inline-src-block (inline-src-block contents info)
+ "Transcode an INLINE-SRC-BLOCK element from Org to LaTeX.
+CONTENTS holds the contents of the item. INFO is a plist holding
+contextual information."
+ (let* ((code (org-element-get-property :value inline-src-block))
+ (separator (org-latex--find-verb-separator code)))
+ (cond
+ ;; Do not use a special package: transcode it verbatim.
+ ((not org-latex-listings)
+ (concat "\\verb" separator code separator))
+ ;; Use minted package.
+ ((eq org-latex-listings 'minted)
+ (let* ((org-lang (org-element-get-property :language inline-src-block))
+ (mint-lang (or (cadr (assq (intern org-lang)
+ org-latex-minted-langs))
+ org-lang))
+ (options (org-latex--make-option-string
+ org-latex-minted-options)))
+ (concat (format "\\mint%s{%s}"
+ (if (string= options "") "" (format "[%s]" options))
+ mint-lang)
+ separator code separator)))
+ ;; Use listings package.
+ (t
+ ;; Maybe translate language's name.
+ (let* ((org-lang (org-element-get-property :language inline-src-block))
+ (lst-lang (or (cadr (assq (intern org-lang)
+ org-latex-listings-langs))
+ org-lang))
+ (options (org-latex--make-option-string
+ (append org-latex-listings-options
+ `(("language" ,lst-lang))))))
+ (concat (format "\\lstinline[%s]" options)
+ separator code separator))))))
+
+
+;;;; Inlinetask
+
+(defun org-latex-inlinetask (inlinetask contents info)
+ "Transcode an INLINETASK element from Org to LaTeX.
+CONTENTS holds the contents of the block. INFO is a plist
+holding contextual information."
+ (let ((title (org-export-secondary-string
+ (org-element-get-property :title inlinetask) 'latex info))
+ (todo (and (plist-get info :with-todo-keywords)
+ (let ((todo (org-element-get-property
+ :todo-keyword inlinetask)))
+ (and todo
+ (org-export-secondary-string todo 'latex info)))))
+ (todo-type (org-element-get-property :todo-type inlinetask))
+ (tags (and (plist-get info :with-tags)
+ (org-element-get-property :tags inlinetask)))
+ (priority (and (plist-get info :with-priority)
+ (org-element-get-property :priority inlinetask))))
+ ;; If `org-latex-format-inlinetask-function' is provided, call it
+ ;; with appropriate arguments.
+ (if (functionp org-latex-format-inlinetask-function)
+ (funcall org-latex-format-inlinetask-function
+ todo todo-type priority title tags contents)
+ ;; Otherwise, use a default template.
+ (org-latex--wrap-label
+ inlinetask
+ (let ((full-title
+ (concat
+ (when todo (format "\\textbf{\\textsf{\\textsc{%s}}} " todo))
+ (when priority (format "\\framebox{\\#%c} " priority))
+ title
+ (when tags (format "\\hfill{}\\textsc{%s}" tags)))))
+ (format (concat "\\begin{center}\n"
+ "\\fbox{\n"
+ "\\begin{minipage}[c]{.6\\textwidth}\n"
+ "%s\n\n"
+ "\\rule[.8em]{\\textwidth}{2pt}\n\n"
+ "%s"
+ "\\end{minipage}\n"
+ "}\n"
+ "\\end{center}")
+ full-title contents))))))
+
+
+;;;; Item
+
+(defun org-latex-item (item contents info)
+ "Transcode an ITEM element from Org to LaTeX.
+CONTENTS holds the contents of the item. INFO is a plist holding
+contextual information."
+ (let* ((level (plist-get (plist-get info :parent-properties) :level))
+ (counter (let ((count (org-element-get-property :counter item)))
+ (and count
+ (< level 4)
+ (format "\\setcounter{enum%s}{%s}\n"
+ (nth level '("i" "ii" "iii" "iv"))
+ (1- count)))))
+ (checkbox (let ((checkbox (org-element-get-property :checkbox item)))
+ (cond ((eq checkbox 'on) "$\\boxtimes$ ")
+ ((eq checkbox 'off) "$\\Box$ ")
+ ((eq checkbox 'trans) "$\\boxminus$ "))))
+ (tag (let ((tag (org-element-get-property :tag item)))
+ (and tag
+ (format "[%s]" (org-export-secondary-string
+ tag 'latex info))))))
+ (concat counter "\\item" tag " " checkbox contents)))
+
+
+;;;; Keyword
+
+(defun org-latex-keyword (keyword contents info)
+ "Transcode a KEYWORD element from Org to LaTeX.
+CONTENTS is nil. INFO is a plist holding contextual information."
+ (let ((key (downcase (org-element-get-property :key keyword)))
+ (value (org-element-get-property :value keyword)))
+ (cond
+ ((string= key "latex") value)
+ ((string= key "index") (format "\\index{%s}" value))
+ ((string= key "target")
+ (format "\\label{%s}" (org-export-solidify-link-text value)))
+ ((string= key "toc")
+ (let ((value (downcase value)))
+ (cond
+ ((string-match "\\<headlines\\>" value)
+ (let ((depth (or (and (string-match "[0-9]+" value)
+ (string-to-number (match-string 0 value)))
+ (plist-get info :with-toc))))
+ (concat
+ (when (wholenump depth)
+ (format "\\setcounter{tocdepth}{%s}\n" depth))
+ "\\tableofcontents")))
+ ((string= "tables" value) "\\listoftables")
+ ((string= "figures" value) "\\listoffigures")
+ ((string= "listings" value) "\\listoflistings"))))
+ ((string= key "include")
+ (org-export-included-file keyword 'latex info)))))
+
+
+;;;; Latex Environment
+
+(defun org-latex-latex-environment (latex-environment contents info)
+ "Transcode a LATEX-ENVIRONMENT element from Org to LaTeX.
+CONTENTS is nil. INFO is a plist holding contextual information."
+ (org-latex--wrap-label
+ latex-environment
+ (org-remove-indentation (org-element-get-property :value latex-environment))))
+
+
+;;;; Latex Fragment
+
+(defun org-latex-latex-fragment (latex-fragment contents info)
+ "Transcode a LATEX-FRAGMENT object from Org to LaTeX.
+CONTENTS is nil. INFO is a plist holding contextual information."
+ (org-element-get-property :value latex-fragment))
+
+
+;;;; Line Break
+
+(defun org-latex-line-break (line-break contents info)
+ "Transcode a LINE-BREAK object from Org to LaTeX.
+CONTENTS is nil. INFO is a plist holding contextual information."
+ "\\\\")
+
+
+;;;; Link
+
+(defun org-latex-link--inline-image (path info)
+ "Return LaTeX code for an image at PATH.
+INFO is a plist containing export options."
+ (let* ((parent-props (plist-get info :parent-properties))
+ (caption (org-latex--caption/label-string
+ (plist-get parent-props :caption)
+ (plist-get parent-props :name)
+ info))
+ ;; Retrieve latex attributes from the element around.
+ (attr (let ((raw-attr
+ (mapconcat #'identity
+ (plist-get parent-props :attr_latex) " ")))
+ (unless (string= raw-attr "") raw-attr)))
+ (disposition
+ (cond
+ ((and attr (string-match "\\<wrap\\>" attr)) 'wrap)
+ ((and attr (string-match "\\<multicolumn\\>" attr)) 'multicolumn)
+ ((or (and attr (string-match "\\<float\\>" attr))
+ (not (string= caption "")))
+ 'float)))
+ (placement
+ (cond
+ ((and attr (string-match "\\<placement=\\(\\S-+\\)" attr))
+ (org-match-string-no-properties 1 attr))
+ ((eq disposition 'wrap) "{l}{0.5\\textwidth}")
+ ((eq disposition 'float)
+ (concat "[" org-latex-default-figure-position "]"))
+ (t ""))))
+ ;; Now clear ATTR from any special keyword and set a default
+ ;; value if nothing is left.
+ (if (not attr)
+ (setq attr "")
+ (while (string-match "\\(wrap\\|multicolumn\\|float\\|placement=\\S-+\\)"
+ attr)
+ (replace-match "" nil nil attr))
+ (setq attr (org-trim attr)))
+ (setq attr (cond ((not (string= attr "")) attr)
+ ((eq disposition 'float) "width=0.7\\textwidth")
+ ((eq disposition 'wrap) "width=0.48\\textwidth")
+ (t (or org-latex-image-default-option ""))))
+ ;; Return proper string, depending on DISPOSITION.
+ (case disposition
+ ('wrap (format "\\begin{wrapfigure}%s
+\\centering
+\\includegraphics[%s]{%s}
+%s\\end{wrapfigure}" placement attr path caption))
+ ('mulicolumn (format "\\begin{figure*}%s
+\\centering
+\\includegraphics[%s]{%s}
+%s\\end{figure*}" placement attr path caption))
+ ('float (format "\\begin{figure}%s
+\\centering
+\\includegraphics[%s]{%s}
+%s\\end{figure}" placement attr path caption))
+ (t (format "\\includegraphics[%s]{%s}" attr path)))))
+
+(defun org-latex-link (link desc info)
+ "Transcode a LINK object from Org to LaTeX.
+
+DESC is the description part of the link, or the empty string.
+INFO is a plist holding contextual information. See
+`org-export-data'."
+ (let* ((type (org-element-get-property :type link))
+ (raw-path (org-element-get-property :path link))
+ ;; Ensure DESC really exists, or set it to nil.
+ (desc (and (not (string= desc "")) desc))
+ (imagep (org-export-inline-image-p
+ link desc org-latex-inline-image-extensions))
+ (path (cond
+ ((member type '("http" "https" "ftp" "mailto"))
+ (concat type ":" raw-path))
+ ((and (not imagep) (string= type "file"))
+ (when (string-match "\\(.+\\)::.+" raw-path)
+ (setq raw-path (match-string 1 raw-path)))
+ (if (file-name-absolute-p raw-path)
+ (concat "file://" (expand-file-name raw-path))
+ ;; TODO: Not implemented yet. Concat also:
+ ;; (org-export-directory :LaTeX info)
+ (concat "file://" raw-path)))
+ (t raw-path)))
+ protocol)
+ (cond
+ ;; Image file.
+ (imagep (org-latex-link--inline-image path info))
+ ;; Id: for now, assume it's an internal link. TODO: do something
+ ;; to check if it isn't in the current file.
+ ((string= type "id")
+ (format "\\hyperref[%s]{%s}" path (or desc path)))
+ ;; Custom-id, target or radioed target: replace link with the
+ ;; normalized custom-id/target name.
+ ((member type '("custom-id" "target" "radio"))
+ (format "\\hyperref[%s]{%s}"
+ (org-export-solidify-link-text path)
+ (or desc (org-export-secondary-string path 'latex info))))
+ ;; Fuzzy: With the help of `org-export-resolve-fuzzy-link', find
+ ;; the destination of the link.
+ ((string= type "fuzzy")
+ (let ((destination (org-export-resolve-fuzzy-link link info)))
+ (cond
+ ;; Target match.
+ ((stringp destination)
+ (format "\\hyperref[%s]{%s}"
+ (org-export-solidify-link-text destination)
+ (or desc
+ (org-export-secondary-string
+ (org-element-get-property :raw-link link) 'latex info))))
+ ;; Headline match.
+ ((integerp destination)
+ (format "\\hyperref[headline-%d]{%s}"
+ destination
+ (or desc
+ (org-export-secondary-string
+ (org-element-get-property :raw-link link) 'latex info))))
+ ;; No match.
+ (t (format "\\texttt{%s}"
+ (or desc
+ (org-export-secondary-string
+ (org-element-get-property :raw-link link)
+ 'latex info)))))))
+ ;; Coderef: replace link with the reference name or the
+ ;; equivalent line number.
+ ((string= type "coderef")
+ (format (org-export-get-coderef-format path (or desc ""))
+ (cdr (assoc path (plist-get info :code-refs)))))
+ ;; Link type is handled by a special function.
+ ((functionp (setq protocol (nth 2 (assoc type org-link-protocols))))
+ (funcall protocol (org-link-unescape path) desc 'latex))
+ ;; External link with a description part.
+ ((and path desc) (format "\\href{%s}{%s}" path desc))
+ ;; External link without a description part.
+ (path (format "\\url{%s}" path))
+ ;; No path, only description. Try to do something useful.
+ (t (format "\\texttt{%s}" desc)))))
+
+
+;;;; Babel Call
+
+;; Babel Calls are ignored.
+
+
+;;;; Macro
+
+(defun org-latex-macro (macro contents info)
+ "Transcode a MACRO element from Org to LaTeX.
+CONTENTS is nil. INFO is a plist holding contextual information."
+ ;; Use available tools.
+ (org-export-expand-macro macro info))
+
+
+;;;; Paragraph
+
+(defun org-latex-paragraph (paragraph contents info)
+ "Transcode a PARAGRAPH element from Org to LaTeX.
+CONTENTS is the contents of the paragraph, as a string. INFO is
+the plist used as a communication channel."
+ contents)
+
+
+;;;; Plain List
+
+(defun org-latex-plain-list (plain-list contents info)
+ "Transcode a PLAIN-LIST element from Org to LaTeX.
+CONTENTS is the contents of the list. INFO is a plist holding
+contextual information."
+ (let* ((type (org-element-get-property :type plain-list))
+ (paralist-types '("inparaenum" "asparaenum" "inparaitem" "asparaitem"
+ "inparadesc" "asparadesc"))
+ (paralist-regexp (concat
+ "\\("
+ (mapconcat 'identity paralist-types "\\|")
+ "\\)"))
+ (attr (mapconcat #'identity
+ (org-element-get-property :attr_latex plain-list)
+ " "))
+ (latex-type (cond
+ ((and attr
+ (string-match
+ (format "\\<%s\\>" paralist-regexp) attr))
+ (match-string 1 attr))
+ ((eq type 'ordered) "enumerate")
+ ((eq type 'unordered) "itemize")
+ ((eq type 'descriptive) "description"))))
+ (org-latex--wrap-label
+ plain-list
+ (format "\\begin{%s}%s\n%s\\end{%s}"
+ latex-type
+ ;; Once special environment, if any, has been removed, the
+ ;; rest of the attributes will be optional arguments.
+ ;; They will be put inside square brackets if necessary.
+ (let ((opt (replace-regexp-in-string
+ (format " *%s *" paralist-regexp) "" attr)))
+ (cond ((string= opt "") "")
+ ((string-match "\\`\\[[^][]+\\]\\'" opt) opt)
+ (t (format "[%s]" opt))))
+ contents
+ latex-type))))
+
+
+;;;; Plain Text
+
+(defun org-latex-plain-text (text info)
+ "Transcode a TEXT string from Org to LaTeX.
+TEXT is the string to transcode. INFO is a plist holding
+contextual information."
+ ;; Protect %, #, &, $, ~, ^, _, { and }.
+ (while (string-match "\\([^\\]\\|^\\)\\([%$#&{}~^_]\\)" text)
+ (setq text
+ (replace-match (format "\\%s" (match-string 2 text)) nil t text 2)))
+ ;; Protect \
+ (setq text (replace-regexp-in-string
+ "\\(?:[^\\]\\|^\\)\\(\\\\\\)\\(?:[^%$#&{}~^_\\]\\|$\\)"
+ "$\\backslash$" text nil t 1))
+ ;; LaTeX into \LaTeX{} and TeX into \TeX{}.
+ (let ((case-fold-search nil)
+ (start 0))
+ (while (string-match "\\<\\(\\(?:La\\)?TeX\\)\\>" text start)
+ (setq text (replace-match
+ (format "\\%s{}" (match-string 1 text)) nil t text)
+ start (match-end 0))))
+ ;; Handle quotation marks
+ (setq text (org-latex--quotation-marks text info))
+ ;; Convert special strings.
+ (when (plist-get info :with-special-strings)
+ (while (string-match (regexp-quote "...") text)
+ (setq text (replace-match "\\ldots{}" nil t text))))
+ ;; Handle break preservation if required.
+ (when (plist-get info :preserve-breaks)
+ (setq text (replace-regexp-in-string "\\(\\\\\\\\\\)?[ \t]*\n" " \\\\\\\\\n"
+ text)))
+ ;; Return value.
+ text)
+
+
+;;;; Property Drawer
+
+(defun org-latex-property-drawer (property-drawer contents info)
+ "Transcode a PROPERTY-DRAWER element from Org to LaTeX.
+CONTENTS is nil. INFO is a plist holding contextual
+information."
+ ;; The property drawer isn't exported but we want separating blank
+ ;; lines nonetheless.
+ "")
+
+
+;;;; Quote Block
+
+(defun org-latex-quote-block (quote-block contents info)
+ "Transcode a QUOTE-BLOCK element from Org to LaTeX.
+CONTENTS holds the contents of the block. INFO is a plist
+holding contextual information."
+ (org-latex--wrap-label
+ quote-block
+ (format "\\begin{quote}\n%s\\end{quote}" contents)))
+
+
+;;;; Quote Section
+
+(defun org-latex-quote-section (quote-section contents info)
+ "Transcode a QUOTE-SECTION element from Org to LaTeX.
+CONTENTS is nil. INFO is a plist holding contextual information."
+ (let ((value (org-remove-indentation
+ (org-element-get-property :value quote-section))))
+ (when value (format "\\begin{verbatim}\n%s\\end{verbatim}" value))))
+
+
+;;;; Radio Target
+
+(defun org-latex-radio-target (radio-target text info)
+ "Transcode a RADIO-TARGET object from Org to LaTeX.
+TEXT is the text of the target. INFO is a plist holding
+contextual information."
+ (format "\\label{%s}%s"
+ (org-export-solidify-link-text
+ (org-element-get-property :raw-value radio-target))
+ text))
+
+
+;;;; Special Block
+
+(defun org-latex-special-block (special-block contents info)
+ "Transcode a SPECIAL-BLOCK element from Org to LaTeX.
+CONTENTS holds the contents of the block. INFO is a plist
+holding contextual information."
+ (let ((type (downcase (org-element-get-property :type special-block))))
+ (org-latex--wrap-label
+ special-block
+ (format "\\begin{%s}\n%s\\end{%s}" type contents type))))
+
+
+;;;; Src Block
+
+(defun org-latex-src-block (src-block contents info)
+ "Transcode a SRC-BLOCK element from Org to LaTeX.
+CONTENTS holds the contents of the item. INFO is a plist holding
+contextual information."
+ (let* ((lang (org-element-get-property :language src-block))
+ (code (org-export-handle-code
+ (org-element-get-property :value src-block)
+ (org-element-get-property :switches src-block)
+ info lang))
+ (caption (org-element-get-property :caption src-block))
+ (label (org-element-get-property :name src-block))
+ (custom-env (and lang
+ (cadr (assq (intern lang)
+ org-latex-custom-lang-environments)))))
+ (cond
+ ;; No source fontification.
+ ((not org-latex-listings)
+ (let ((caption-str (org-latex--caption/label-string
+ caption label info))
+ (float-env (when caption "\\begin{figure}[H]\n%s\n\\end{figure}")))
+ (format (or float-env "%s")
+ (concat
+ caption-str
+ (format "\\begin{verbatim}\n%s\\end{verbatim}" code)))))
+ ;; Custom environment.
+ (custom-env
+ (format "\\begin{%s}\n%s\\end{%s}\n" custom-env code custom-env))
+ ;; Use minted package.
+ ((eq org-latex-listings 'minted)
+ (let* ((mint-lang (or (cadr (assq (intern lang) org-latex-minted-langs))
+ lang))
+ (float-env (when (or label caption)
+ (format "\\begin{listing}[H]\n%%s\n%s\\end{listing}"
+ (org-latex--caption/label-string
+ caption label info))))
+ (body (format "\\begin{minted}[%s]{%s}\n%s\\end{minted}"
+ (org-latex--make-option-string
+ org-latex-minted-options)
+ mint-lang code)))
+ (if float-env (format float-env body) body)))
+ ;; Use listings package.
+ (t
+ (let ((lst-lang (or (cadr (assq (intern lang) org-latex-listings-langs))
+ lang))
+ (caption-str (and caption
+ (org-export-secondary-string
+ (org-element-get-property :caption src-block)
+ 'latex info))))
+ (concat (format "\\lstset{%s}\n"
+ (org-latex--make-option-string
+ (append org-latex-listings-options
+ `(("language" ,lst-lang))
+ (when label `(("label" ,label)))
+ (when caption-str
+ `(("caption" ,caption-str))))))
+ (format "\\begin{lstlisting}\n%s\\end{lstlisting}" code)))))))
+
+
+;;;; Statistics Cookie
+
+(defun org-latex-statistics-cookie (statistics-cookie contents info)
+ "Transcode a STATISTICS-COOKIE object from Org to LaTeX.
+CONTENTS is nil. INFO is a plist holding contextual information."
+ (org-element-get-property :value statistics-cookie))
+
+
+;;;; Subscript
+
+(defun org-latex-subscript (subscript contents info)
+ "Transcode a SUBSCRIPT object from Org to LaTeX.
+CONTENTS is the contents of the object. INFO is a plist holding
+contextual information."
+ (format (if (= (length contents) 1) "$_%s$" "$_{\\mathrm{%s}}$") contents))
+
+
+;;;; Superscript
+
+(defun org-latex-superscript (superscript contents info)
+ "Transcode a SUPERSCRIPT object from Org to LaTeX.
+CONTENTS is the contents of the object. INFO is a plist holding
+contextual information."
+ (format (if (= (length contents) 1) "$^%s$" "$^{\\mathrm{%s}}$") contents))
+
+
+;;;; Table
+
+(defun org-latex-table--format-string (table info)
+ "Return an appropriate format string for TABLE.
+
+INFO is the plist containing format info about the table, as
+returned by `org-export-table-format-info'.
+
+The format string one placeholder for the body of the table."
+ (let* ((label (org-element-get-property :name table))
+ (caption (org-latex--caption/label-string
+ (org-element-get-property :caption table) label info))
+ (attr (mapconcat #'identity
+ (org-element-get-property :attr_latex table)
+ " "))
+ ;; Determine alignment string.
+ (alignment (org-latex-table--align-string attr info))
+ ;; Determine environment for the table: longtable, tabular...
+ (table-env (cond
+ ((not attr) org-latex-default-table-environment)
+ ((string-match "\\<longtable\\>" attr) "longtable")
+ ((string-match "\\(tabular.\\)" attr)
+ (org-match-string-no-properties 1 attr))
+ (t org-latex-default-table-environment)))
+ ;; If table is a float, determine environment: table or table*.
+ (float-env (cond
+ ((string= "longtable" table-env) nil)
+ ((and attr
+ (or (string-match (regexp-quote "table*") attr)
+ (string-match "\\<multicolumn\\>" attr)))
+ "table*")
+ ((or (not (string= caption "")) label) "table")))
+ ;; Extract others display options.
+ (width (and attr
+ (string-match "\\<width=\\(\\S-+\\)" attr)
+ (org-match-string-no-properties 1 attr)))
+ (placement (if (and attr
+ (string-match "\\<placement=\\(\\S-+\\)" attr))
+ (org-match-string-no-properties 1 attr)
+ (concat "["
+ org-latex-default-figure-position
+ "]"))))
+ ;; Prepare the final format string for the table.
+ (cond
+ ;; Longtable.
+ ((string= "longtable" table-env)
+ (format "\\begin{longtable}{%s}\n%s\n%%s\n%s\\end{longtable}"
+ alignment
+ (if (or (not org-latex-table-caption-above)
+ (string= "" caption))
+ ""
+ (concat (org-trim caption) "\\\\"))
+ (if (or org-latex-table-caption-above
+ (string= "" caption))
+ ""
+ (concat (org-trim caption) "\\\\\n"))))
+ ;; Others.
+ (t (concat (when float-env
+ (concat
+ (format "\\begin{%s}%s\n" float-env placement)
+ (if org-latex-table-caption-above caption "")))
+ (when org-latex-tables-centered "\\begin{center}\n")
+ (format "\\begin{%s}%s{%s}\n%%s\n\\end{%s}"
+ table-env
+ (if width (format "{%s}" width) "")
+ alignment
+ table-env)
+ (when org-latex-tables-centered "\n\\end{center}")
+ (when float-env
+ (concat (if org-latex-table-caption-above "" caption)
+ (format "\n\\end{%s}" float-env))))))))
+
+(defun org-latex-table--align-string (attr info)
+ "Return an appropriate LaTeX alignment string.
+
+INFO is the plist containing format info about the table, as
+returned by `org-export-table-format-info'."
+ (or (and attr
+ (string-match "\\<align=\\(\\S-+\\)" attr)
+ (match-string 1 attr))
+ (let* ((align (copy-sequence (plist-get info :alignment)))
+ (colgroups (copy-sequence (plist-get info :column-groups)))
+ (cols (length align))
+ (separators (make-vector (1+ cols) "")))
+ ;; Ignore the first column if it's special.
+ (when (plist-get info :special-column-p)
+ (aset align 0 "") (aset colgroups 0 nil))
+ (let ((col 0))
+ (mapc (lambda (el)
+ (let ((gr (aref colgroups col)))
+ (when (memq gr '(start start-end))
+ (aset separators col "|"))
+ (when (memq gr '(end start-end))
+ (aset separators (1+ col) "|")))
+ (incf col))
+ align))
+ ;; Build the LaTeX specific alignment string.
+ (loop for al across align
+ for sep across separators
+ concat (concat sep al) into output
+ finally return (concat output (aref separators cols))))))
+
+(defun org-latex-table (table contents info)
+ "Transcode a TABLE element from Org to LaTeX.
+CONTENTS is nil. INFO is a plist holding contextual information."
+ (let ((attr (mapconcat #'identity
+ (org-element-get-property :attr_latex table)
+ " "))
+ (raw-table (org-element-get-property :raw-table table)))
+ (cond
+ ;; Case 1: verbatim table.
+ ((or org-latex-tables-verbatim
+ (and attr (string-match "\\<verbatim\\>" attr)))
+ (format "\\begin{verbatim}\n%s\n\\end{verbatim}"
+ (org-export-clean-table
+ raw-table
+ (plist-get (org-export-table-format-info raw-table)
+ :special-column-p))))
+ ;; Case 2: table.el table. Convert it using appropriate tools.
+ ((eq (org-element-get-property :type table) 'table.el)
+ (require 'table)
+ ;; Ensure "*org-export-table*" buffer is empty.
+ (and (get-buffer "*org-export-table*")
+ (kill-buffer (get-buffer "*org-export-table*")))
+ (let ((output (with-temp-buffer
+ (insert raw-table)
+ (goto-char 1)
+ (re-search-forward "^[ \t]*|[^|]" nil t)
+ (table-generate-source 'latex "*org-export-table*")
+ (with-current-buffer "*org-export-table*"
+ (org-trim (buffer-string))))))
+ (kill-buffer (get-buffer "*org-export-table*"))
+ ;; Remove left out comments.
+ (while (string-match "^%.*\n" output)
+ (setq output (replace-match "" t t output)))
+ ;; When the "rmlines" attribute is provided, remove all hlines
+ ;; but the the one separating heading from the table body.
+ (when (and attr (string-match "\\<rmlines\\>" attr))
+ (let ((n 0) (pos 0))
+ (while (and (< (length output) pos)
+ (setq pos (string-match "^\\\\hline\n?" output pos)))
+ (incf n)
+ (unless (= n 2) (setq output (replace-match "" nil nil output))))))
+ (if org-latex-tables-centered
+ (format "\\begin{center}\n%s\n\\end{center}" output)
+ output)))
+ ;; Case 3: Standard table.
+ (t (let* (
+ (info (org-export-table-format-info raw-table))
+ (clean-table (org-export-clean-table
+ raw-table (plist-get info :special-column-p)))
+ (columns-number (length (plist-get info :alignment))))
+ ;; Convert ROWS to send them to `orgtbl-to-latex'. In
+ ;; particular, send each cell to
+ ;; `org-element-parse-secondary-string' to expand any Org
+ ;; object within. Eventually, flesh the format string out with
+ ;; the table.
+ (format (org-latex-table--format-string table info)
+ (orgtbl-to-latex
+ (mapcar
+ (lambda (row)
+ (if (string-match org-table-hline-regexp row)
+ 'hline
+ (mapcar
+ (lambda (cell)
+ (org-export-secondary-string
+ (org-element-parse-secondary-string
+ cell
+ (cdr (assq 'table org-element-string-restrictions)))
+ 'latex info))
+ (org-split-string row "[ \t]*|[ \t]*"))))
+ (org-split-string clean-table "\n"))
+ `(:tstart nil :tend nil
+ ;; Longtable environment requires specific
+ ;; header line end.
+ :hlend ,(and attr
+ (string-match "\\<longtable\\>" attr)
+ (format "\\\\
+\\hline
+\\endhead
+\\hline\\multicolumn{%d}{r}{Continued on next page}\\\\
+\\endfoot
+\\endlastfoot"
+ columns-number))))))))))
+
+
+;;;; Target
+
+(defun org-latex-target (target text info)
+ "Transcode a TARGET object from Org to LaTeX.
+TEXT is the text of the target. INFO is a plist holding
+contextual information."
+ (format "\\label{%s}%s"
+ (org-export-solidify-link-text
+ (org-element-get-property :raw-value target))
+ text))
+
+
+;;;; Time-stamp
+
+(defun org-latex-time-stamp (time-stamp contents info)
+ "Transcode a TIME-STAMP object from Org to LaTeX.
+CONTENTS is nil. INFO is a plist holding contextual information."
+ (let ((value (org-element-get-property :value time-stamp))
+ (type (org-element-get-property :type time-stamp))
+ (appt-type (org-element-get-property :appt-type time-stamp)))
+ (concat (cond ((eq appt-type 'scheduled)
+ (format "\\textbf{\\textsc{%s}} " org-scheduled-string))
+ ((eq appt-type 'deadline)
+ (format "\\textbf{\\textsc{%s}} " org-deadline-string))
+ ((eq appt-type 'closed)
+ (format "\\textbf{\\textsc{%s}} " org-closed-string)))
+ (cond ((memq type '(active active-range))
+ (format org-latex-active-timestamp-format value))
+ ((memq type '(inactive inactive-range))
+ (format org-latex-inactive-timestamp-format value))
+ (t
+ (format org-latex-diary-timestamp-format value))))))
+
+
+;;;; Verbatim
+
+(defun org-latex-verbatim (element contents info)
+ "Return verbatim text in LaTeX."
+ (let ((fmt (cdr (assoc (org-element-get-property :marker element)
+ org-latex-emphasis-alist)))
+ (value (org-element-get-property :value element)))
+ (cond
+ ;; Handle the `verb' special case.
+ ((eq 'verb fmt)
+ (let ((separator (org-latex--find-verb-separator value)))
+ (concat "\\verb" separator value separator)))
+ ;; Handle the `protectedtexttt' special case.
+ ((eq 'protectedtexttt fmt)
+ (let ((start 0)
+ (trans '(("\\" . "\\textbackslash{}")
+ ("~" . "\\textasciitilde{}")
+ ("^" . "\\textasciicircum{}")))
+ (rtn "")
+ char)
+ (while (string-match "[\\{}$%&_#~^]" value)
+ (setq char (match-string 0 value))
+ (if (> (match-beginning 0) 0)
+ (setq rtn (concat rtn (substring value 0 (match-beginning 0)))))
+ (setq value (substring value (1+ (match-beginning 0))))
+ (setq char (or (cdr (assoc char trans)) (concat "\\" char))
+ rtn (concat rtn char)))
+ (setq value (concat rtn value)
+ fmt "\\texttt{%s}")
+ (while (string-match "--" value)
+ (setq value (replace-match "-{}-" t t value)))
+ (format fmt value)))
+ ;; Else use format string.
+ (t (format fmt value)))))
+
+
+;;;; Verse Block
+
+(defun org-latex-verse-block (verse-block contents info)
+ "Transcode a VERSE-BLOCK element from Org to LaTeX.
+CONTENTS is nil. INFO is a plist holding contextual information."
+ (org-latex--wrap-label
+ verse-block
+ ;; In a verse environment, add a line break to each newline
+ ;; character and change each white space at beginning of a line
+ ;; into a space of 1 em. Also change each blank line with
+ ;; a vertical space of 1 em.
+ (progn
+ (setq contents (replace-regexp-in-string
+ "^ *\\\\\\\\$" "\\\\vspace*{1em}"
+ (replace-regexp-in-string
+ "\\(\\\\\\\\\\)?[ \t]*\n" " \\\\\\\\\n"
+ (org-remove-indentation
+ (org-export-secondary-string
+ (org-element-get-property :value verse-block)
+ 'latex info)))))
+ (while (string-match "^[ \t]+" contents)
+ (let ((new-str (format "\\hspace*{%dem}"
+ (length (match-string 0 contents)))))
+ (setq contents (replace-match new-str nil t contents))))
+ (format "\\begin{verse}\n%s\\end{verse}" contents))))
+
+
+(provide 'org-latex)
+;;; org-latex.el ends here