diff options
Diffstat (limited to 'elpa/org-9.5.2/ox-latex.el')
-rw-r--r-- | elpa/org-9.5.2/ox-latex.el | 3828 |
1 files changed, 3828 insertions, 0 deletions
diff --git a/elpa/org-9.5.2/ox-latex.el b/elpa/org-9.5.2/ox-latex.el new file mode 100644 index 0000000..c45dc98 --- /dev/null +++ b/elpa/org-9.5.2/ox-latex.el @@ -0,0 +1,3828 @@ +;;; ox-latex.el --- LaTeX Back-End for Org Export Engine -*- lexical-binding: t; -*- + +;; Copyright (C) 2011-2021 Free Software Foundation, Inc. + +;; Author: Nicolas Goaziou <n.goaziou at gmail dot com> +;; Keywords: outlines, hypermedia, calendar, wp + +;; This file is part of GNU Emacs. + +;; GNU Emacs 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. + +;; GNU Emacs 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: +;; +;; See Org manual for details. + +;;; Code: + +(require 'cl-lib) +(require 'ox) +(require 'ox-publish) + +;;; Function Declarations + +(defvar org-latex-default-packages-alist) +(defvar org-latex-packages-alist) +(defvar orgtbl-exp-regexp) + + + +;;; Define Back-End + +(org-export-define-backend 'latex + '((bold . org-latex-bold) + (center-block . org-latex-center-block) + (clock . org-latex-clock) + (code . org-latex-code) + (drawer . org-latex-drawer) + (dynamic-block . org-latex-dynamic-block) + (entity . org-latex-entity) + (example-block . org-latex-example-block) + (export-block . org-latex-export-block) + (export-snippet . org-latex-export-snippet) + (fixed-width . org-latex-fixed-width) + (footnote-definition . org-latex-footnote-definition) + (footnote-reference . org-latex-footnote-reference) + (headline . org-latex-headline) + (horizontal-rule . org-latex-horizontal-rule) + (inline-src-block . org-latex-inline-src-block) + (inlinetask . org-latex-inlinetask) + (italic . org-latex-italic) + (item . org-latex-item) + (keyword . org-latex-keyword) + (latex-environment . org-latex-latex-environment) + (latex-fragment . org-latex-latex-fragment) + (line-break . org-latex-line-break) + (link . org-latex-link) + (node-property . org-latex-node-property) + (paragraph . org-latex-paragraph) + (plain-list . org-latex-plain-list) + (plain-text . org-latex-plain-text) + (planning . org-latex-planning) + (property-drawer . org-latex-property-drawer) + (quote-block . org-latex-quote-block) + (radio-target . org-latex-radio-target) + (section . org-latex-section) + (special-block . org-latex-special-block) + (src-block . org-latex-src-block) + (statistics-cookie . org-latex-statistics-cookie) + (strike-through . org-latex-strike-through) + (subscript . org-latex-subscript) + (superscript . org-latex-superscript) + (table . org-latex-table) + (table-cell . org-latex-table-cell) + (table-row . org-latex-table-row) + (target . org-latex-target) + (template . org-latex-template) + (timestamp . org-latex-timestamp) + (underline . org-latex-underline) + (verbatim . org-latex-verbatim) + (verse-block . org-latex-verse-block) + ;; Pseudo objects and elements. + (latex-math-block . org-latex-math-block) + (latex-matrices . org-latex-matrices)) + :menu-entry + '(?l "Export to LaTeX" + ((?L "As LaTeX buffer" org-latex-export-as-latex) + (?l "As LaTeX file" org-latex-export-to-latex) + (?p "As PDF file" org-latex-export-to-pdf) + (?o "As PDF file and open" + (lambda (a s v b) + (if a (org-latex-export-to-pdf t s v b) + (org-open-file (org-latex-export-to-pdf nil s v b))))))) + :filters-alist '((:filter-options . org-latex-math-block-options-filter) + (:filter-paragraph . org-latex-clean-invalid-line-breaks) + (:filter-parse-tree org-latex-math-block-tree-filter + org-latex-matrices-tree-filter + org-latex-image-link-filter) + (:filter-verse-block . org-latex-clean-invalid-line-breaks)) + :options-alist + '((:latex-class "LATEX_CLASS" nil org-latex-default-class t) + (:latex-class-options "LATEX_CLASS_OPTIONS" nil nil t) + (:latex-header "LATEX_HEADER" nil nil newline) + (:latex-header-extra "LATEX_HEADER_EXTRA" nil nil newline) + (:description "DESCRIPTION" nil nil parse) + (:keywords "KEYWORDS" nil nil parse) + (:subtitle "SUBTITLE" nil nil parse) + ;; Other variables. + (:latex-active-timestamp-format nil nil org-latex-active-timestamp-format) + (:latex-caption-above nil nil org-latex-caption-above) + (:latex-classes nil nil org-latex-classes) + (:latex-default-figure-position nil nil org-latex-default-figure-position) + (:latex-default-table-environment nil nil org-latex-default-table-environment) + (:latex-default-quote-environment nil nil org-latex-default-quote-environment) + (:latex-default-table-mode nil nil org-latex-default-table-mode) + (:latex-diary-timestamp-format nil nil org-latex-diary-timestamp-format) + (:latex-footnote-defined-format nil nil org-latex-footnote-defined-format) + (:latex-footnote-separator nil nil org-latex-footnote-separator) + (:latex-format-drawer-function nil nil org-latex-format-drawer-function) + (:latex-format-headline-function nil nil org-latex-format-headline-function) + (:latex-format-inlinetask-function nil nil org-latex-format-inlinetask-function) + (:latex-hyperref-template nil nil org-latex-hyperref-template t) + (:latex-image-default-scale nil nil org-latex-image-default-scale) + (:latex-image-default-height nil nil org-latex-image-default-height) + (:latex-image-default-option nil nil org-latex-image-default-option) + (:latex-image-default-width nil nil org-latex-image-default-width) + (:latex-images-centered nil nil org-latex-images-centered) + (:latex-inactive-timestamp-format nil nil org-latex-inactive-timestamp-format) + (:latex-inline-image-rules nil nil org-latex-inline-image-rules) + (:latex-link-with-unknown-path-format nil nil org-latex-link-with-unknown-path-format) + (:latex-listings nil nil org-latex-listings) + (:latex-listings-langs nil nil org-latex-listings-langs) + (:latex-listings-options nil nil org-latex-listings-options) + (:latex-minted-langs nil nil org-latex-minted-langs) + (:latex-minted-options nil nil org-latex-minted-options) + (:latex-prefer-user-labels nil nil org-latex-prefer-user-labels) + (:latex-subtitle-format nil nil org-latex-subtitle-format) + (:latex-subtitle-separate nil nil org-latex-subtitle-separate) + (:latex-table-scientific-notation nil nil org-latex-table-scientific-notation) + (:latex-tables-booktabs nil nil org-latex-tables-booktabs) + (:latex-tables-centered nil nil org-latex-tables-centered) + (:latex-text-markup-alist nil nil org-latex-text-markup-alist) + (:latex-title-command nil nil org-latex-title-command) + (:latex-toc-command nil nil org-latex-toc-command) + (:latex-compiler "LATEX_COMPILER" nil org-latex-compiler) + ;; Redefine regular options. + (:date "DATE" nil "\\today" parse))) + + + +;;; Internal Variables + +(defconst org-latex-babel-language-alist + '(("af" . "afrikaans") + ("bg" . "bulgarian") + ("ca" . "catalan") + ("cs" . "czech") + ("cy" . "welsh") + ("da" . "danish") + ("de" . "germanb") + ("de-at" . "naustrian") + ("de-de" . "ngerman") + ("el" . "greek") + ("en" . "english") + ("en-au" . "australian") + ("en-ca" . "canadian") + ("en-gb" . "british") + ("en-ie" . "irish") + ("en-nz" . "newzealand") + ("en-us" . "american") + ("es" . "spanish") + ("et" . "estonian") + ("eu" . "basque") + ("fi" . "finnish") + ("fr" . "french") + ("fr-ca" . "canadien") + ("gl" . "galician") + ("hr" . "croatian") + ("hu" . "hungarian") + ("id" . "indonesian") + ("is" . "icelandic") + ("it" . "italian") + ("la" . "latin") + ("ms" . "malay") + ("nl" . "dutch") + ("nb" . "norsk") + ("nn" . "nynorsk") + ("no" . "norsk") + ("pl" . "polish") + ("pt" . "portuguese") + ("pt-br" . "brazilian") + ("ro" . "romanian") + ("ru" . "russian") + ("sa" . "sanskrit") + ("sb" . "uppersorbian") + ("sk" . "slovak") + ("sl" . "slovene") + ("sq" . "albanian") + ("sr" . "serbian") + ("sv" . "swedish") + ("ta" . "tamil") + ("tr" . "turkish") + ("uk" . "ukrainian")) + "Alist between language code and corresponding Babel option.") + +(defconst org-latex-polyglossia-language-alist + '(("am" "amharic") + ("ar" "arabic") + ("ast" "asturian") + ("bg" "bulgarian") + ("bn" "bengali") + ("bo" "tibetan") + ("br" "breton") + ("ca" "catalan") + ("cop" "coptic") + ("cs" "czech") + ("cy" "welsh") + ("da" "danish") + ("de" "german" "german") + ("de-at" "german" "austrian") + ("de-de" "german" "german") + ("dsb" "lsorbian") + ("dv" "divehi") + ("el" "greek") + ("en" "english" "usmax") + ("en-au" "english" "australian") + ("en-gb" "english" "uk") + ("en-nz" "english" "newzealand") + ("en-us" "english" "usmax") + ("eo" "esperanto") + ("es" "spanish") + ("et" "estonian") + ("eu" "basque") + ("fa" "farsi") + ("fi" "finnish") + ("fr" "french") + ("fu" "friulan") + ("ga" "irish") + ("gd" "scottish") + ("gl" "galician") + ("he" "hebrew") + ("hi" "hindi") + ("hr" "croatian") + ("hsb" "usorbian") + ("hu" "magyar") + ("hy" "armenian") + ("ia" "interlingua") + ("id" "bahasai") + ("is" "icelandic") + ("it" "italian") + ("kn" "kannada") + ("la" "latin" "modern") + ("la-classic" "latin" "classic") + ("la-medieval" "latin" "medieval") + ("la-modern" "latin" "modern") + ("lo" "lao") + ("lt" "lithuanian") + ("lv" "latvian") + ("ml" "malayalam") + ("mr" "maranthi") + ("nb" "norsk") + ("nko" "nko") + ("nl" "dutch") + ("nn" "nynorsk") + ("no" "norsk") + ("oc" "occitan") + ("pl" "polish") + ("pms" "piedmontese") + ("pt" "portuges") + ("pt-br" "brazilian") + ("rm" "romansh") + ("ro" "romanian") + ("ru" "russian") + ("sa" "sanskrit") + ("se" "samin") + ("sk" "slovak") + ("sl" "slovenian") + ("sq" "albanian") + ("sr" "serbian") + ("sv" "swedish") + ("syr" "syriac") + ("ta" "tamil") + ("te" "telugu") + ("th" "thai") + ("tk" "turkmen") + ("tr" "turkish") + ("uk" "ukrainian") + ("ur" "urdu") + ("vi" "vietnamese")) + "Alist between language code and corresponding Polyglossia option.") + +(defconst org-latex-table-matrix-macros '(("bordermatrix" . "\\cr") + ("qbordermatrix" . "\\cr") + ("kbordermatrix" . "\\\\")) + "Alist between matrix macros and their row ending.") + +(defconst org-latex-math-environments-re + (format + "\\`[ \t]*\\\\begin{%s\\*?}" + (regexp-opt + '("equation" "eqnarray" "math" "displaymath" + "align" "gather" "multline" "flalign" "alignat" + "xalignat" "xxalignat" + "subequations" + ;; breqn + "dmath" "dseries" "dgroup" "darray" + ;; empheq + "empheq"))) + "Regexp of LaTeX math environments.") + + +;;; User Configurable Variables + +(defgroup org-export-latex nil + "Options for exporting Org mode files to LaTeX." + :tag "Org Export LaTeX" + :group 'org-export) + +;;;; Generic + +(defcustom org-latex-caption-above '(table) + "When non-nil, place caption string at the beginning of elements. +Otherwise, place it near the end. When value is a list of +symbols, put caption above selected elements only. Allowed +symbols are: `image', `table', `src-block' and `special-block'." + :group 'org-export-latex + :version "26.1" + :package-version '(Org . "8.3") + :type '(choice + (const :tag "For all elements" t) + (const :tag "For no element" nil) + (set :tag "For the following elements only" :greedy t + (const :tag "Images" image) + (const :tag "Tables" table) + (const :tag "Source code" src-block) + (const :tag "Special blocks" special-block)))) + +(defcustom org-latex-prefer-user-labels nil + "Use user-provided labels instead of internal ones when non-nil. + +When this variable is non-nil, Org will use the value of +CUSTOM_ID property, NAME keyword or Org target as the key for the +\\label commands generated. + +By default, Org generates its own internal labels during LaTeX +export. This process ensures that the \\label keys are unique +and valid, but it means the keys are not available in advance of +the export process. + +Setting this variable gives you control over how Org generates +labels during LaTeX export, so that you may know their keys in +advance. One reason to do this is that it allows you to refer to +various elements using a single label both in Org's link syntax +and in embedded LaTeX code. + +For example, when this variable is non-nil, a headline like this: + + ** Some section + :PROPERTIES: + :CUSTOM_ID: sec:foo + :END: + This is section [[#sec:foo]]. + #+BEGIN_EXPORT latex + And this is still section \\ref{sec:foo}. + #+END_EXPORT + +will be exported to LaTeX as: + + \\subsection{Some section} + \\label{sec:foo} + This is section \\ref{sec:foo}. + And this is still section \\ref{sec:foo}. + +A non-default value of `org-latex-reference-command' will change the +command (\\ref by default) used to create label references. + +Note, however, that setting this variable introduces a limitation +on the possible values for CUSTOM_ID and NAME. When this +variable is non-nil, Org passes their value to \\label unchanged. +You are responsible for ensuring that the value is a valid LaTeX +\\label key, and that no other \\label commands with the same key +appear elsewhere in your document. (Keys may contain letters, +numbers, and the following punctuation: `_' `.' `-' `:'.) There +are no such limitations on CUSTOM_ID and NAME when this variable +is nil. + +For headlines that do not define the CUSTOM_ID property or +elements without a NAME, Org will continue to use its default +labeling scheme to generate labels and resolve links into proper +references." + :group 'org-export-latex + :type 'boolean + :version "26.1" + :package-version '(Org . "8.3")) + +(defcustom org-latex-reference-command "\\ref{%s}" + "Format string that takes a reference to produce a LaTeX reference command. + +The reference is a label such as sec:intro. A format string of \"\\ref{%s}\" +produces numbered references and will always work. It may be desirable to make +use of a package such as hyperref or cleveref and then change the format string +to \"\\autoref{%s}\" or \"\\cref{%s}\" for example." + :group 'org-export-latex + :type 'string + :package-version '(Org . "9.5") + :safe #'stringp) + +;;;; 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:\" and + \"#+LATEX_HEADER_EXTRA:\" keywords. + +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(_EXTRA) + [NO-EXTRA] do not include #+LATEX_HEADER(_EXTRA) stuff + +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 and #+LATEX_HEADER_EXTRA lines, then have a call +to \\providecommand, and then place \\usepackage commands based +on the content of `org-latex-packages-alist'. + +If your header, `org-latex-default-packages-alist' or +`org-latex-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. + +Likewise, if your header contains \"\\usepackage[AUTO]{babel}\" +or \"\\usepackage[AUTO]{polyglossia}\", AUTO will be replaced +with the language related to the language code specified by +`org-export-default-language'. Note that constructions such as +\"\\usepackage[french,AUTO,english]{babel}\" are permitted. For +Polyglossia the language will be set via the macros +\"\\setmainlanguage\" and \"\\setotherlanguage\". See also +`org-latex-guess-babel-language' and +`org-latex-guess-polyglossia-language'. + +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-title-command "\\maketitle" + "The command used to insert the title just after \\begin{document}. + +This format string may contain these elements: + + %a for AUTHOR keyword + %t for TITLE keyword + %s for SUBTITLE keyword + %k for KEYWORDS line + %d for DESCRIPTION line + %c for CREATOR line + %l for Language keyword + %L for capitalized language keyword + %D for DATE keyword + +If you need to use a \"%\" character, you need to escape it +like that: \"%%\". + +Setting :latex-title-command in publishing projects will take +precedence over this variable." + :group 'org-export-latex + :type '(string :tag "Format string")) + +(defcustom org-latex-subtitle-format "\\\\\\medskip\n\\large %s" + "Format string used for transcoded subtitle. +The format string should have at most one \"%s\"-expression, +which is replaced with the subtitle." + :group 'org-export-latex + :version "26.1" + :package-version '(Org . "8.3") + :type '(string :tag "Format string")) + +(defcustom org-latex-subtitle-separate nil + "Non-nil means the subtitle is not typeset as part of title." + :group 'org-export-latex + :version "26.1" + :package-version '(Org . "8.3") + :type 'boolean) + +(defcustom org-latex-toc-command "\\tableofcontents\n\n" + "LaTeX command to set the table of contents, list of figures, etc. +This command only applies to the table of contents generated with +the toc:nil option, not to those generated with #+TOC keyword." + :group 'org-export-latex + :type 'string) + +(defcustom org-latex-hyperref-template + "\\hypersetup{\n pdfauthor={%a},\n pdftitle={%t},\n pdfkeywords={%k}, + pdfsubject={%d},\n pdfcreator={%c}, \n pdflang={%L}}\n" + "Template for hyperref package options. + +This format string may contain these elements: + + %a for AUTHOR keyword + %t for TITLE keyword + %s for SUBTITLE keyword + %k for KEYWORDS line + %d for DESCRIPTION line + %c for CREATOR line + %l for Language keyword + %L for capitalized language keyword + %D for DATE keyword + +If you need to use a \"%\" character, you need to escape it +like that: \"%%\". + +As a special case, a nil value prevents template from being +inserted. + +Setting :latex-hyperref-template in publishing projects will take +precedence over this variable." + :group 'org-export-latex + :version "26.1" + :package-version '(Org . "8.3") + :type '(choice (const :tag "No template" nil) + (string :tag "Format string"))) + +;;;; Headline + +(defcustom org-latex-format-headline-function + 'org-latex-format-headline-default-function + "Function for formatting the headline's text. + +This function will be called with six 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 (list of strings or nil) +INFO the export options (plist) + +The function result will be used in the section format string." + :group 'org-export-latex + :version "24.4" + :package-version '(Org . "8.0") + :type 'function) + + +;;;; Footnotes + +(defcustom org-latex-footnote-separator "\\textsuperscript{,}\\," + "Text used to separate footnotes." + :group 'org-export-latex + :type 'string) + +(defcustom org-latex-footnote-defined-format "\\textsuperscript{\\ref{%s}}" + "Format string used to format reference to footnote already defined. +%s will be replaced by the label of the referred footnote." + :group 'org-export-latex + :type '(choice + (const :tag "Use plain superscript (default)" "\\textsuperscript{\\ref{%s}}") + (const :tag "Use Memoir/KOMA-Script footref" "\\footref{%s}") + (string :tag "Other format string")) + :version "26.1" + :package-version '(Org . "9.0")) + +;;;; Timestamps + +(defcustom org-latex-active-timestamp-format "\\textit{%s}" + "A printf format string to be applied to active timestamps." + :group 'org-export-latex + :type 'string) + +(defcustom org-latex-inactive-timestamp-format "\\textit{%s}" + "A printf format string to be applied to inactive timestamps." + :group 'org-export-latex + :type 'string) + +(defcustom org-latex-diary-timestamp-format "\\textit{%s}" + "A printf format string to be applied to diary timestamps." + :group 'org-export-latex + :type 'string) + + +;;;; Links + +(defcustom org-latex-images-centered t + "When non-nil, images are centered." + :group 'org-export-latex + :version "26.1" + :package-version '(Org . "9.0") + :type 'boolean + :safe #'booleanp) + +(defcustom org-latex-image-default-option "" + "Default option for images." + :group 'org-export-latex + :version "24.4" + :package-version '(Org . "8.0") + :type 'string) + +(defcustom org-latex-image-default-width ".9\\linewidth" + "Default width for images. +This value will not be used if a height is provided." + :group 'org-export-latex + :version "24.4" + :package-version '(Org . "8.0") + :type 'string) + +(defcustom org-latex-image-default-scale "" + "Default scale for images. +This value will not be used if a width or a scale is provided, +or if the image is wrapped within a \"wrapfigure\" environment. +Scale overrides width and height." + :group 'org-export-latex + :package-version '(Org . "9.3") + :type 'string + :safe #'stringp) + +(defcustom org-latex-image-default-height "" + "Default height for images. +This value will not be used if a width is provided, or if the +image is wrapped within a \"figure\" or \"wrapfigure\" +environment." + :group 'org-export-latex + :version "24.4" + :package-version '(Org . "8.0") + :type 'string) + +(defcustom org-latex-default-figure-position "htbp" + "Default position for LaTeX figures." + :group 'org-export-latex + :type 'string + :version "26.1" + :package-version '(Org . "9.0") + :safe #'stringp) + +(defcustom org-latex-inline-image-rules + `(("file" . ,(rx "." + (or "pdf" "jpeg" "jpg" "png" "ps" "eps" "tikz" "pgf" "svg") + eos))) + "Rules characterizing image files that can be inlined into LaTeX. + +A rule consists in an association whose key is the type of link +to consider, and value is a regexp that will be matched against +link's path. + +Note that, by default, 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 + :package-version '(Org . "9.4") + :type '(alist :key-type (string :tag "Type") + :value-type (regexp :tag "Path"))) + +(defcustom org-latex-link-with-unknown-path-format "\\texttt{%s}" + "Format string for links with unknown path type." + :group 'org-export-latex + :type 'string) + + +;;;; Tables + +(defcustom org-latex-default-table-environment "tabular" + "Default environment used to build tables." + :group 'org-export-latex + :version "24.4" + :package-version '(Org . "8.0") + :type 'string) + +(defcustom org-latex-default-quote-environment "quote" + "Default environment used to `quote' blocks." + :group 'org-export-latex + :package-version '(Org . "9.5") + :type 'string + :safe #'stringp) + +(defcustom org-latex-default-table-mode 'table + "Default mode for tables. + +Value can be a symbol among: + + `table' Regular LaTeX table. + + `math' In this mode, every cell is considered as being in math + mode and the complete table will be wrapped within a math + environment. It is particularly useful to write matrices. + + `inline-math' This mode is almost the same as `math', but the + math environment will be inlined. + + `verbatim' The table is exported as it appears in the Org + buffer, within a verbatim environment. + +This value can be overridden locally with, i.e. \":mode math\" in +LaTeX attributes. + +When modifying this variable, it may be useful to change +`org-latex-default-table-environment' accordingly." + :group 'org-export-latex + :version "24.4" + :package-version '(Org . "8.0") + :type '(choice (const :tag "Table" table) + (const :tag "Matrix" math) + (const :tag "Inline matrix" inline-math) + (const :tag "Verbatim" verbatim)) + :safe (lambda (s) (memq s '(table math inline-math verbatim)))) + +(defcustom org-latex-tables-centered t + "When non-nil, tables are exported in a center environment." + :group 'org-export-latex + :type 'boolean + :safe #'booleanp) + +(defcustom org-latex-tables-booktabs nil + "When non-nil, display tables in a formal \"booktabs\" style. +This option assumes that the \"booktabs\" package is properly +loaded in the header of the document. This value can be ignored +locally with \":booktabs t\" and \":booktabs nil\" LaTeX +attributes." + :group 'org-export-latex + :version "24.4" + :package-version '(Org . "8.0") + :type 'boolean + :safe #'booleanp) + +(defcustom org-latex-table-scientific-notation nil + "Format string to display numbers in scientific notation. + +The format should have \"%s\" twice, for mantissa and exponent +\(i.e., \"%s\\\\times10^{%s}\"). + +When nil, no transformation is made." + :group 'org-export-latex + :version "24.4" + :package-version '(Org . "8.0") + :type '(choice + (string :tag "Format string") + (const :tag "No formatting" nil))) + +;;;; Text markup + +(defcustom org-latex-text-markup-alist '((bold . "\\textbf{%s}") + (code . protectedtexttt) + (italic . "\\emph{%s}") + (strike-through . "\\sout{%s}") + (underline . "\\uline{%s}") + (verbatim . protectedtexttt)) + "Alist of LaTeX expressions to convert text markup. + +The key must be a symbol among `bold', `code', `italic', +`strike-through', `underline' and `verbatim'. 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. + +If no association can be found for a given markup, text will be +returned as-is." + :group 'org-export-latex + :version "26.1" + :package-version '(Org . "8.3") + :type 'alist + :options '(bold code italic strike-through underline verbatim)) + + +;;;; Drawers + +(defcustom org-latex-format-drawer-function (lambda (_ contents) contents) + "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. + +The default function simply returns the value of CONTENTS." + :group 'org-export-latex + :version "26.1" + :package-version '(Org . "8.3") + :type 'function) + + +;;;; Inlinetasks + +(defcustom org-latex-format-inlinetask-function + 'org-latex-format-inlinetask-default-function + "Function called to format an inlinetask in LaTeX code. + +The function must accept seven parameters: + TODO the todo keyword (string or nil) + TODO-TYPE the todo type (symbol: `todo', `done', nil) + PRIORITY the inlinetask priority (integer or nil) + NAME the inlinetask name (string) + TAGS the inlinetask tags (list of strings or nil) + CONTENTS the contents of the inlinetask (string or nil) + INFO the export options (plist) + +The function should return the string to be exported." + :group 'org-export-latex + :type 'function + :version "26.1" + :package-version '(Org . "8.3")) + + +;; 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 \\='ox-latex) + (add-to-list \\='org-latex-packages-alist \\='(\"\" \"listings\")) + (add-to-list \\='org-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 \\='ox-latex) + (add-to-list \\='org-latex-packages-alist \\='(\"newfloat\" \"minted\")) + +In addition, it is necessary to install pygments +\(URL `https://pygments.org>'), and to configure the variable +`org-latex-pdf-process' so that the -shell-escape option is +passed to pdflatex. + +The minted choice has possible repercussions on the preview of +latex fragments (see `org-preview-latex-fragment'). If you run +into previewing problems, please consult +URL `https://orgmode.org/worg/org-tutorials/org-latex-preview.html'." + :group 'org-export-latex + :type '(choice + (const :tag "Use listings" t) + (const :tag "Use minted" minted) + (const :tag "Export verbatim" nil)) + :safe (lambda (s) (memq s '(t nil minted)))) + +(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 "[LaTeX]TeX") + (shell-script "bash") + (gnuplot "Gnuplot") + (ocaml "[Objective]Caml") (caml "Caml") + (sql "SQL") (sqlite "sql") + (makefile "make") + (R "r")) + "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 + :version "26.1" + :package-version '(Org . "8.3") + :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-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. If you need block-specific options, you may use the +following syntax: + + #+ATTR_LATEX: :options key1=value1,key2=value2 + #+BEGIN_SRC <LANG> + ... + #+END_SRC" + :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-latex-minted-options + \\='((\"bgcolor\" \"bg\") (\"frame\" \"lines\"))) + +will result in source 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. If you need +block-specific options, you may use the following syntax: + + #+ATTR_LATEX: :options key1=value1,key2=value2 + #+BEGIN_SRC <LANG> + ... + #+END_SRC" + :group 'org-export-latex + :type '(repeat + (list + (string :tag "Minted option name ") + (string :tag "Minted option value")))) + +(defcustom org-latex-custom-lang-environments nil + "Alist mapping languages to language-specific LaTeX environments. + +It is used during export of source blocks by the listings and +minted LaTeX packages. The environment may be a simple string, +composed of only letters and numbers. In this case, the string +is directly the name of the LaTeX environment to use. The +environment may also be a format string. In this case the format +string will be directly exported. This format string may contain +these elements: + + %s for the formatted source + %c for the caption + %f for the float attribute + %l for an appropriate label + %o for the LaTeX attributes + +For example, + + (setq org-latex-custom-lang-environments + \\='((python \"pythoncode\") + (ocaml \"\\\\begin{listing} +\\\\begin{minted}[%o]{ocaml} +%s\\\\end{minted} +\\\\caption{%c} +\\\\label{%l}\"))) + +would have the effect that if Org encounters a Python source block +during LaTeX export it will produce + + \\begin{pythoncode} + <source block body> + \\end{pythoncode} + +and if Org encounters an Ocaml source block during LaTeX export it +will produce + + \\begin{listing} + \\begin{minted}[<attr_latex options>]{ocaml} + <source block body> + \\end{minted} + \\caption{<caption>} + \\label{<label>} + \\end{listing}" + :group 'org-export-latex + :type '(repeat + (list + (symbol :tag "Language name ") + (string :tag "Environment name or format string"))) + :version "26.1" + :package-version '(Org . "9.0")) + + +;;;; Compilation + +(defcustom org-latex-compiler-file-string "%% Intended LaTeX compiler: %s\n" + "LaTeX compiler format-string. +See also `org-latex-compiler'." + :group 'org-export-latex + :type '(choice + (const :tag "Comment" "%% Intended LaTeX compiler: %s\n") + (const :tag "latex-mode file variable" "%% -*- latex-run-command: %s -*-\n") + (const :tag "AUCTeX file variable" "%% -*- LaTeX-command: %s -*-\n") + (string :tag "custom format" "%% %s")) + :version "26.1" + :package-version '(Org . "9.0")) + +(defcustom org-latex-compiler "pdflatex" + "LaTeX compiler to use. + +Must be an element in `org-latex-compilers' or the empty quote. +Can also be set in buffers via #+LATEX_COMPILER. See also +`org-latex-compiler-file-string'." + :group 'org-export-latex + :type '(choice + (const :tag "pdfLaTeX" "pdflatex") + (const :tag "XeLaTeX" "xelatex") + (const :tag "LuaLaTeX" "lualatex") + (const :tag "Unset" "")) + :version "26.1" + :package-version '(Org . "9.0")) + +(defconst org-latex-compilers '("pdflatex" "xelatex" "lualatex") + "Known LaTeX compilers. +See also `org-latex-compiler'.") + +(defcustom org-latex-bib-compiler "bibtex" + "Command to process a LaTeX file's bibliography. + +The shorthand %bib in `org-latex-pdf-process' is replaced with +this value. + +A better approach is to use a compiler suit such as `latexmk'." + :group 'org-export-latex + :type '(choice (const :tag "BibTeX" "bibtex") + (const :tag "Biber" "biber") + (string :tag "Other process")) + :version "26.1" + :package-version '(Org . "9.0")) + +(defcustom org-latex-pdf-process + (if (executable-find "latexmk") + '("latexmk -f -pdf -%latex -interaction=nonstopmode -output-directory=%o %f") + '("%latex -interaction nonstopmode -output-directory %o %f" + "%latex -interaction nonstopmode -output-directory %o %f" + "%latex -interaction nonstopmode -output-directory %o %f")) + "Commands to process a LaTeX file to a PDF file. + +This is a list of strings, each of them will be given to the +shell as a command. %f in the command will be replaced by the +relative file name, %F by the absolute file name, %b by the file +base name (i.e. without directory and extension parts), %o by the +base directory of the file, %O by the absolute file name of the +output file, %latex is the LaTeX compiler (see +`org-latex-compiler'), and %bib is the BibTeX-like compiler (see +`org-latex-bib-compiler'). + +The reason why this is a list is that it usually takes several +runs of `pdflatex', maybe mixed with a call to `bibtex'. Org +does not have a clever mechanism to detect which of these +commands have to be run to get to a stable result, and it also +does not do any error checking. + +Consider a smart LaTeX compiler such as `texi2dvi' or `latexmk', +which calls the \"correct\" combinations of auxiliary programs. + +Alternatively, this may be a Lisp function that does the +processing, so you could use this to apply the machinery of +AUCTeX or the Emacs LaTeX mode. This function should accept the +file name as its single argument." + :group 'org-export-pdf + :type '(choice + (repeat :tag "Shell command sequence" + (string :tag "Shell command")) + (const :tag "2 runs of latex" + ("%latex -interaction nonstopmode -output-directory %o %f" + "%latex -interaction nonstopmode -output-directory %o %f")) + (const :tag "3 runs of latex" + ("%latex -interaction nonstopmode -output-directory %o %f" + "%latex -interaction nonstopmode -output-directory %o %f" + "%latex -interaction nonstopmode -output-directory %o %f")) + (const :tag "latex,bibtex,latex,latex" + ("%latex -interaction nonstopmode -output-directory %o %f" + "%bib %b" + "%latex -interaction nonstopmode -output-directory %o %f" + "%latex -interaction nonstopmode -output-directory %o %f")) + (const :tag "texi2dvi" + ("cd %o; LATEX=\"%latex\" texi2dvi -p -b -V %b.tex")) + (const :tag "latexmk" + ("latexmk -f -pdf -%latex -interaction=nonstopmode -output-directory=%o %f")) + (function))) + +(defcustom org-latex-logfiles-extensions + '("aux" "bcf" "blg" "fdb_latexmk" "fls" "figlist" "idx" "log" "nav" "out" + "ptc" "run.xml" "snm" "toc" "vrb" "xdv") + "The list of file extensions to consider as LaTeX logfiles. +The logfiles will be removed if `org-latex-remove-logfiles' is +non-nil." + :group 'org-export-latex + :version "26.1" + :package-version '(Org . "8.3") + :type '(repeat (string :tag "Extension"))) + +(defcustom org-latex-remove-logfiles t + "Non-nil means remove the logfiles produced by PDF production. +By default, logfiles are files with these extensions: .aux, .idx, +.log, .out, .toc, .nav, .snm and .vrb. To define the set of +logfiles to remove, set `org-latex-logfiles-extensions'." + :group 'org-export-latex + :type 'boolean) + +(defcustom org-latex-known-warnings + '(("Reference.*?undefined" . "[undefined reference]") + ("Runaway argument" . "[runaway argument]") + ("Underfull \\hbox" . "[underfull hbox]") + ("Overfull \\hbox" . "[overfull hbox]") + ("Citation.*?undefined" . "[undefined citation]") + ("Undefined control sequence" . "[undefined control sequence]")) + "Alist of regular expressions and associated messages for the user. +The regular expressions are used to find possible warnings in the +log of a LaTeX-run. These warnings will be reported after +calling `org-latex-compile'." + :group 'org-export-latex + :version "26.1" + :package-version '(Org . "8.3") + :type '(repeat + (cons + (regexp :tag "Regexp") + (string :tag "Message")))) + + + +;;; Internal Functions + +(defun org-latex--caption-above-p (element info) + "Non-nil when caption is expected to be located above ELEMENT. +INFO is a plist holding contextual information." + (let ((above (plist-get info :latex-caption-above))) + (if (symbolp above) above + (let ((type (org-element-type element))) + (memq (if (eq type 'link) 'image type) above))))) + +(defun org-latex--label (datum info &optional force full) + "Return an appropriate label for DATUM. +DATUM is an element or a `target' type object. INFO is the +current export state, as a plist. + +Return nil if element DATUM has no NAME or VALUE affiliated +keyword or no CUSTOM_ID property, unless FORCE is non-nil. In +this case always return a unique label. + +Eventually, if FULL is non-nil, wrap label within \"\\label{}\"." + (let* ((type (org-element-type datum)) + (user-label + (org-element-property + (cl-case type + ((headline inlinetask) :CUSTOM_ID) + (target :value) + (otherwise :name)) + datum)) + (label + (and (or user-label force) + (if (and user-label (plist-get info :latex-prefer-user-labels)) + user-label + (concat (pcase type + (`headline "sec:") + (`table "tab:") + (`latex-environment + (and (string-match-p + org-latex-math-environments-re + (org-element-property :value datum)) + "eq:")) + (`latex-matrices "eq:") + (`paragraph + (and (org-element-property :caption datum) + "fig:")) + (_ nil)) + (org-export-get-reference datum info)))))) + (cond ((not full) label) + (label (format "\\label{%s}%s" + label + (if (eq type 'target) "" "\n"))) + (t "")))) + +(defun org-latex--caption/label-string (element info) + "Return caption and label LaTeX string for ELEMENT. + +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* ((label (org-latex--label element info nil t)) + (main (org-export-get-caption element)) + (attr (org-export-read-attribute :attr_latex element)) + (type (org-element-type element)) + (nonfloat (or (and (plist-member attr :float) + (not (plist-get attr :float)) + main) + (and (eq type 'src-block) + (not (plist-get attr :float)) + (null (plist-get info :latex-listings))))) + (short (org-export-get-caption element t)) + (caption-from-attr-latex (plist-get attr :caption))) + (cond + ((org-string-nw-p caption-from-attr-latex) + (concat caption-from-attr-latex "\n")) + ((and (not main) (equal label "")) "") + ((not main) label) + ;; Option caption format with short name. + (t + (format (if nonfloat "\\captionof{%s}%s{%s%s}\n" + "\\caption%s%s{%s%s}\n") + (let ((type* (if (eq type 'latex-environment) + (org-latex--environment-type element) + type))) + (if nonfloat + (cl-case type* + (paragraph "figure") + (image "figure") + (special-block "figure") + (src-block (if (plist-get info :latex-listings) + "listing" + "figure")) + (t (symbol-name type*))) + "")) + (if short (format "[%s]" (org-export-data short info)) "") + (org-trim label) + (org-export-data main info)))))) + +(defun org-latex-guess-inputenc (header) + "Set the coding system in inputenc to what the buffer is. + +HEADER is the LaTeX header string. This function only applies +when specified inputenc option is \"AUTO\". + +Return the new header, as a string." + (let* ((cs (or (ignore-errors + (latexenc-coding-system-to-inputenc + (or org-export-coding-system 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-guess-babel-language (header info) + "Set Babel's language according to LANGUAGE keyword. + +HEADER is the LaTeX header string. INFO is the plist used as +a communication channel. + +Insertion of guessed language only happens when Babel package has +explicitly been loaded. Then it is added to the rest of +package's options. + +The argument to Babel may be \"AUTO\" which is then replaced with +the language of the document or `org-export-default-language' +unless language in question is already loaded. + +Return the new header." + (let ((language-code (plist-get info :language))) + ;; If no language is set or Babel package is not loaded, return + ;; HEADER as-is. + (if (or (not (stringp language-code)) + (not (string-match "\\\\usepackage\\[\\(.*\\)\\]{babel}" header))) + header + (let ((options (save-match-data + (org-split-string (match-string 1 header) ",[ \t]*"))) + (language (cdr (assoc-string language-code + org-latex-babel-language-alist t)))) + ;; If LANGUAGE is already loaded, return header without AUTO. + ;; Otherwise, replace AUTO with language or append language if + ;; AUTO is not present. + (replace-match + (mapconcat (lambda (option) (if (equal "AUTO" option) language option)) + (cond ((member language options) (delete "AUTO" options)) + ((member "AUTO" options) options) + (t (append options (list language)))) + ", ") + t nil header 1))))) + +(defun org-latex-guess-polyglossia-language (header info) + "Set the Polyglossia language according to the LANGUAGE keyword. + +HEADER is the LaTeX header string. INFO is the plist used as +a communication channel. + +Insertion of guessed language only happens when the Polyglossia +package has been explicitly loaded. + +The argument to Polyglossia may be \"AUTO\" which is then +replaced with the language of the document or +`org-export-default-language'. Note, the language is really set +using \setdefaultlanguage and not as an option to the package. + +Return the new header." + (let ((language (plist-get info :language))) + ;; If no language is set or Polyglossia is not loaded, return + ;; HEADER as-is. + (if (or (not (stringp language)) + (not (string-match + "\\\\usepackage\\(?:\\[\\([^]]+?\\)\\]\\){polyglossia}\n" + header))) + header + (let* ((options (org-string-nw-p (match-string 1 header))) + (languages (and options + ;; Reverse as the last loaded language is + ;; the main language. + (nreverse + (delete-dups + (save-match-data + (org-split-string + (replace-regexp-in-string + "AUTO" language options t) + ",[ \t]*")))))) + (main-language-set + (string-match-p "\\\\setmainlanguage{.*?}" header))) + (replace-match + (concat "\\usepackage{polyglossia}\n" + (mapconcat + (lambda (l) + (let ((l (or (assoc l org-latex-polyglossia-language-alist) + l))) + (format (if main-language-set "\\setotherlanguage%s{%s}\n" + (setq main-language-set t) + "\\setmainlanguage%s{%s}\n") + (if (and (consp l) (= (length l) 3)) + (format "[variant=%s]" (nth 2 l)) + "") + (nth 1 l)))) + languages + "")) + t t header 0))))) + +(defun org-latex--remove-packages (pkg-alist info) + "Remove packages based on the current LaTeX compiler. + +PKG-ALIST is a list of packages, as in `org-latex-packages-alist' +and `org-latex-default-packages-alist'. If the fourth argument +of a package is neither nil nor a member of the LaTeX compiler +associated to the document, the package is removed. + +Return new list of packages." + (let ((compiler (or (plist-get info :latex-compiler) ""))) + (if (not (member-ignore-case compiler org-latex-compilers)) pkg-alist + (cl-remove-if-not + (lambda (package) + (pcase package + (`(,_ ,_ ,_ nil) t) + (`(,_ ,_ ,_ ,compilers) (member-ignore-case compiler compilers)) + (_ t))) + pkg-alist)))) + +(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<>()[]{}")) + (cl-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) + (pcase-let ((`(,keyword ,value) pair)) + (concat keyword + (and (> (length value) 0) + (concat "=" + (if (string-match-p (rx (any "[]")) value) + (format "{%s}" value) + value)))))) + options + ",")) + +(defun org-latex--wrap-label (element output info) + "Wrap label associated to ELEMENT around OUTPUT, if appropriate. +INFO is the current export state, as a plist. This function +should not be used for floats. See +`org-latex--caption/label-string'." + (if (not (and (org-string-nw-p output) (org-element-property :name element))) + output + (concat (format "\\phantomsection\n\\label{%s}\n" + (org-latex--label element info)) + output))) + +(defun org-latex--protect-text (text) + "Protect special characters in string TEXT and return it." + (replace-regexp-in-string "[\\{}$%&_#~^]" "\\\\\\&" text)) + +(defun org-latex--text-markup (text markup info) + "Format TEXT depending on MARKUP text markup. +INFO is a plist used as a communication channel. See +`org-latex-text-markup-alist' for details." + (let ((fmt (cdr (assq markup (plist-get info :latex-text-markup-alist))))) + (cl-case fmt + ;; No format string: Return raw text. + ((nil) text) + ;; Handle the `verb' special case: Find an appropriate separator + ;; and use "\\verb" command. + (verb + (let ((separator (org-latex--find-verb-separator text))) + (concat "\\verb" + separator + (replace-regexp-in-string "\n" " " text) + separator))) + (protectedtexttt (org-latex--protect-texttt text)) + ;; Else use format string. + (t (format fmt text))))) + +(defun org-latex--protect-texttt (text) + "Protect special chars, then wrap TEXT in \"\\texttt{}\"." + (format "\\texttt{%s}" + (replace-regexp-in-string + "--\\|[\\{}$%&_#~^]" + (lambda (m) + (cond ((equal m "--") "-{}-") + ((equal m "\\") "\\textbackslash{}") + ((equal m "~") "\\textasciitilde{}") + ((equal m "^") "\\textasciicircum{}") + (t (org-latex--protect-text m)))) + text nil t))) + +(defun org-latex--delayed-footnotes-definitions (element info) + "Return footnotes definitions in ELEMENT as a string. + +INFO is a plist used as a communication channel. + +Footnotes definitions are returned within \"\\footnotetext{}\" +commands. + +This function is used within constructs that don't support +\"\\footnote{}\" command (e.g., an item tag). In that case, +\"\\footnotemark\" is used within the construct and the function +just outside of it." + (mapconcat + (lambda (ref) + (let ((def (org-export-get-footnote-definition ref info))) + (format "\\footnotetext[%d]{%s%s}" + (org-export-get-footnote-number ref info) + (org-trim (org-latex--label def info t t)) + (org-trim (org-export-data def info))))) + ;; Find every footnote reference in ELEMENT. + (letrec ((all-refs nil) + (search-refs + (lambda (data) + ;; Return a list of all footnote references never seen + ;; before in DATA. + (org-element-map data 'footnote-reference + (lambda (ref) + (when (org-export-footnote-first-reference-p ref info) + (push ref all-refs) + (when (eq (org-element-property :type ref) 'standard) + (funcall search-refs + (org-export-get-footnote-definition ref info))))) + info) + (reverse all-refs)))) + (funcall search-refs element)) + "")) + +(defun org-latex--translate (s info) + "Translate string S according to specified language. +INFO is a plist used as a communication channel." + (org-export-translate s :latex info)) + +(defun org-latex--format-spec (info) + "Create a format-spec for document meta-data. +INFO is a plist used as a communication channel." + (let ((language (let ((lang (plist-get info :language))) + (or (cdr (assoc-string lang org-latex-babel-language-alist t)) + (nth 1 (assoc-string lang org-latex-polyglossia-language-alist t)) + lang)))) + `((?a . ,(org-export-data (plist-get info :author) info)) + (?t . ,(org-export-data (plist-get info :title) info)) + (?s . ,(org-export-data (plist-get info :subtitle) info)) + (?k . ,(org-export-data (org-latex--wrap-latex-math-block + (plist-get info :keywords) info) + info)) + (?d . ,(org-export-data (org-latex--wrap-latex-math-block + (plist-get info :description) info) + info)) + (?c . ,(plist-get info :creator)) + (?l . ,language) + (?L . ,(capitalize language)) + (?D . ,(org-export-get-date info))))) + +(defun org-latex--insert-compiler (info) + "Insert LaTeX_compiler info into the document. +INFO is a plist used as a communication channel." + (let ((compiler (plist-get info :latex-compiler))) + (and (org-string-nw-p org-latex-compiler-file-string) + (member (or compiler "") org-latex-compilers) + (format org-latex-compiler-file-string compiler)))) + + +;;; Filters + +(defun org-latex-matrices-tree-filter (tree _backend info) + (org-latex--wrap-latex-matrices tree info)) + +(defun org-latex-math-block-tree-filter (tree _backend info) + (org-latex--wrap-latex-math-block tree info)) + +(defun org-latex-math-block-options-filter (info _backend) + (dolist (prop '(:author :date :title) info) + (plist-put info prop + (org-latex--wrap-latex-math-block (plist-get info prop) info)))) + +(defun org-latex-clean-invalid-line-breaks (data _backend _info) + (replace-regexp-in-string + "\\(\\\\end{[A-Za-z0-9*]+}\\|^\\)[ \t]*\\\\\\\\[ \t]*$" "\\1" + data)) + + +;;; Template + +;;;###autoload +(defun org-latex-make-preamble (info &optional template snippet?) + "Return a formatted LaTeX preamble. +INFO is a plist used as a communication channel. Optional +argument TEMPLATE, when non-nil, is the header template string, +as expected by `org-splice-latex-header'. When SNIPPET? is +non-nil, only includes packages relevant to image generation, as +specified in `org-latex-default-packages-alist' or +`org-latex-packages-alist'." + (let* ((class (plist-get info :latex-class)) + (class-template + (or template + (let* ((class-options (plist-get info :latex-class-options)) + (header (nth 1 (assoc class (plist-get info :latex-classes))))) + (and (stringp header) + (if (not class-options) header + (replace-regexp-in-string + "^[ \t]*\\\\documentclass\\(\\(\\[[^]]*\\]\\)?\\)" + class-options header t nil 1)))) + (user-error "Unknown LaTeX class `%s'" class)))) + (org-latex-guess-polyglossia-language + (org-latex-guess-babel-language + (org-latex-guess-inputenc + (org-element-normalize-string + (org-splice-latex-header + class-template + (org-latex--remove-packages org-latex-default-packages-alist info) + (org-latex--remove-packages org-latex-packages-alist info) + snippet? + (mapconcat #'org-element-normalize-string + (list (plist-get info :latex-header) + (and (not snippet?) + (plist-get info :latex-header-extra))) + "")))) + info) + info))) + +(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-data (plist-get info :title) info)) + (spec (org-latex--format-spec info))) + (concat + ;; Time-stamp. + (and (plist-get info :time-stamp-file) + (format-time-string "%% Created %Y-%m-%d %a %H:%M\n")) + ;; LaTeX compiler. + (org-latex--insert-compiler info) + ;; Document class and packages. + (org-latex-make-preamble info) + ;; Possibly limit depth for headline numbering. + (let ((sec-num (plist-get info :section-numbers))) + (when (integerp sec-num) + (format "\\setcounter{secnumdepth}{%d}\n" sec-num))) + ;; Author. + (let ((author (and (plist-get info :with-author) + (let ((auth (plist-get info :author))) + (and auth (org-export-data auth info))))) + (email (and (plist-get info :with-email) + (org-export-data (plist-get info :email) info)))) + (cond ((and author email (not (string= "" email))) + (format "\\author{%s\\thanks{%s}}\n" author email)) + ((or author email) (format "\\author{%s}\n" (or author email))))) + ;; Date. + (let ((date (and (plist-get info :with-date) (org-export-get-date info)))) + (format "\\date{%s}\n" (org-export-data date info))) + ;; Title and subtitle. + (let* ((subtitle (plist-get info :subtitle)) + (formatted-subtitle + (when subtitle + (format (plist-get info :latex-subtitle-format) + (org-export-data subtitle info)))) + (separate (plist-get info :latex-subtitle-separate))) + (concat + (format "\\title{%s%s}\n" title + (if separate "" (or formatted-subtitle ""))) + (when (and separate subtitle) + (concat formatted-subtitle "\n")))) + ;; Hyperref options. + (let ((template (plist-get info :latex-hyperref-template))) + (and (stringp template) + (format-spec template spec))) + ;; Document start. + "\\begin{document}\n\n" + ;; Title command. + (let* ((title-command (plist-get info :latex-title-command)) + (command (and (stringp title-command) + (format-spec title-command spec)))) + (org-element-normalize-string + (cond ((not (plist-get info :with-title)) nil) + ((string= "" title) nil) + ((not (stringp command)) nil) + ((string-match "\\(?:[^%]\\|^\\)%s" command) + (format command title)) + (t command)))) + ;; Table of contents. + (let ((depth (plist-get info :with-toc))) + (when depth + (concat (when (integerp depth) + (format "\\setcounter{tocdepth}{%d}\n" depth)) + (plist-get info :latex-toc-command)))) + ;; Document's body. + contents + ;; Creator. + (and (plist-get info :with-creator) + (concat (plist-get info :creator) "\n")) + ;; Document end. + "\\end{document}"))) + + + +;;; Transcode Functions + +;;;; Bold + +(defun org-latex-bold (_bold contents info) + "Transcode BOLD from Org to LaTeX. +CONTENTS is the text with bold markup. INFO is a plist holding +contextual information." + (org-latex--text-markup contents 'bold info)) + + +;;;; Center 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 center block. INFO is a plist +holding contextual information." + (org-latex--wrap-label + center-block (format "\\begin{center}\n%s\\end{center}" contents) info)) + + +;;;; Clock + +(defun org-latex-clock (clock _contents info) + "Transcode a CLOCK element from Org to LaTeX. +CONTENTS is nil. INFO is a plist holding contextual +information." + (concat + "\\noindent" + (format "\\textbf{%s} " org-clock-string) + (format (plist-get info :latex-inactive-timestamp-format) + (concat (org-timestamp-translate (org-element-property :value clock)) + (let ((time (org-element-property :duration clock))) + (and time (format " (%s)" time))))) + "\\\\")) + + +;;;; Code + +(defun org-latex-code (code _contents info) + "Transcode a CODE object from Org to LaTeX. +CONTENTS is nil. INFO is a plist used as a communication +channel." + (org-latex--text-markup (org-element-property :value code) 'code info)) + + +;;;; 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-property :drawer-name drawer)) + (output (funcall (plist-get info :latex-format-drawer-function) + name contents))) + (org-latex--wrap-label drawer output info))) + + +;;;; 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 info)) + + +;;;; 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." + (org-element-property :latex entity)) + + +;;;; Example Block + +(defun org-latex-example-block (example-block _contents info) + "Transcode an EXAMPLE-BLOCK element from Org to LaTeX. +CONTENTS is nil. INFO is a plist holding contextual +information." + (when (org-string-nw-p (org-element-property :value example-block)) + (let ((environment (or (org-export-read-attribute + :attr_latex example-block :environment) + "verbatim"))) + (org-latex--wrap-label + example-block + (format "\\begin{%s}\n%s\\end{%s}" + environment + (org-export-format-code-default example-block info) + environment) + info)))) + + +;;;; 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 (member (org-element-property :type export-block) '("LATEX" "TEX")) + (org-remove-indentation (org-element-property :value export-block)))) + + +;;;; 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." + (when (eq (org-export-snippet-backend export-snippet) 'latex) + (org-element-property :value export-snippet))) + + +;;;; 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." + (org-latex--wrap-label + fixed-width + (format "\\begin{verbatim}\n%s\n\\end{verbatim}" + (org-remove-indentation + (org-element-property :value fixed-width))) + info)) + + +;;;; 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." + (let ((label (org-element-property :label footnote-reference))) + (concat + ;; Insert separator between two footnotes in a row. + (let ((prev (org-export-get-previous-element footnote-reference info))) + (when (eq (org-element-type prev) 'footnote-reference) + (plist-get info :latex-footnote-separator))) + (cond + ;; Use `:latex-footnote-defined-format' if the footnote has + ;; already been defined. + ((not (org-export-footnote-first-reference-p footnote-reference info)) + (format (plist-get info :latex-footnote-defined-format) + (org-latex--label + (org-export-get-footnote-definition footnote-reference info) + info t))) + ;; Use \footnotemark if reference is within another footnote + ;; reference, footnote definition, table cell, verse block, or + ;; item's tag. + ((or (org-element-lineage footnote-reference + '(footnote-reference footnote-definition + table-cell verse-block)) + (eq 'item (org-element-type + (org-export-get-parent-element footnote-reference)))) + "\\footnotemark") + ;; Otherwise, define it with \footnote command. + (t + (let ((def (org-export-get-footnote-definition footnote-reference info))) + (concat + (format "\\footnote{%s%s}" (org-trim (org-export-data def info)) + ;; Only insert a \label if there exist another + ;; reference to def. + (cond ((not label) "") + ((org-element-map (plist-get info :parse-tree) + 'footnote-reference + (lambda (f) + (and (not (eq f footnote-reference)) + (equal (org-element-property :label f) label) + (org-trim (org-latex--label def info t t)))) + info t)) + (t ""))) + ;; Retrieve all footnote references within the footnote and + ;; add their definition after it, since LaTeX doesn't support + ;; them inside. + (org-latex--delayed-footnotes-definitions def info)))))))) + + +;;;; Headline + +(defun org-latex-headline (headline contents info) + "Transcode a HEADLINE element from Org to LaTeX. +CONTENTS holds the contents of the headline. INFO is a plist +holding contextual information." + (unless (org-element-property :footnote-section-p headline) + (let* ((class (plist-get info :latex-class)) + (level (org-export-get-relative-level headline info)) + (numberedp (org-export-numbered-headline-p headline info)) + (class-sectioning (assoc class (plist-get info :latex-classes))) + ;; Section formatting will set two placeholders: one for + ;; the title and the other for the contents. + (section-fmt + (let ((sec (if (functionp (nth 2 class-sectioning)) + (funcall (nth 2 class-sectioning) level numberedp) + (nth (1+ level) class-sectioning)))) + (cond + ;; No section available for that LEVEL. + ((not sec) nil) + ;; Section format directly returned by a function. Add + ;; placeholder for contents. + ((stringp sec) (concat sec "\n%s")) + ;; (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))))))) + ;; Create a temporary export back-end that hard-codes + ;; "\underline" within "\section" and alike. + (section-back-end + (org-export-create-backend + :parent 'latex + :transcoders + '((underline . (lambda (o c i) (format "\\underline{%s}" c))) + ;; LaTeX isn't happy when you try to use \verb inside the argument of other + ;; commands (like \section, etc.), and this causes compilation to fail. + ;; So, within headings it's a good idea to replace any instances of \verb + ;; with \texttt. + (code . (lambda (o _ _) (org-latex--protect-texttt (org-element-property :value o)))) + (verbatim . (lambda (o _ _) (org-latex--protect-texttt (org-element-property :value o))))))) + (text + (org-export-data-with-backend + (org-element-property :title headline) section-back-end info)) + (todo + (and (plist-get info :with-todo-keywords) + (let ((todo (org-element-property :todo-keyword headline))) + (and todo (org-export-data todo info))))) + (todo-type (and todo (org-element-property :todo-type headline))) + (tags (and (plist-get info :with-tags) + (org-export-get-tags headline info))) + (priority (and (plist-get info :with-priority) + (org-element-property :priority headline))) + ;; Create the headline text along with a no-tag version. + ;; The latter is required to remove tags from toc. + (full-text (funcall (plist-get info :latex-format-headline-function) + todo todo-type priority text tags info)) + ;; Associate \label to the headline for internal links. + (headline-label (org-latex--label headline info t t)) + (pre-blanks + (make-string (org-element-property :pre-blank headline) ?\n))) + (if (or (not section-fmt) (org-export-low-level-p headline info)) + ;; 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. + (let ((low-level-body + (concat + ;; If 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" + (and full-text + (string-match-p "\\`[ \t]*\\[" full-text) + "\\relax") + " " full-text "\n" + headline-label + pre-blanks + contents))) + ;; If headline is not the last sibling simply return + ;; LOW-LEVEL-BODY. Otherwise, also close the list, before + ;; any blank line. + (if (not (org-export-last-sibling-p headline info)) low-level-body + (replace-regexp-in-string + "[ \t\n]*\\'" + (format "\n\\\\end{%s}" (if numberedp 'enumerate 'itemize)) + low-level-body))) + ;; This is a standard headline. Export it as a section. Add + ;; an alternative heading when possible, and when this is not + ;; identical to the usual heading. + (let ((opt-title + (funcall (plist-get info :latex-format-headline-function) + todo todo-type priority + (org-export-data-with-backend + (org-export-get-alt-title headline info) + section-back-end info) + (and (eq (plist-get info :with-tags) t) tags) + info)) + ;; Maybe end local TOC (see `org-latex-keyword'). + (contents + (concat + contents + (let ((case-fold-search t) + (section + (let ((first (car (org-element-contents headline)))) + (and (eq (org-element-type first) 'section) first)))) + (org-element-map section 'keyword + (lambda (k) + (and (equal (org-element-property :key k) "TOC") + (let ((v (org-element-property :value k))) + (and (string-match-p "\\<headlines\\>" v) + (string-match-p "\\<local\\>" v) + (format "\\stopcontents[level-%d]" level))))) + info t))))) + (if (and opt-title + (not (equal opt-title full-text)) + (string-match "\\`\\\\\\(.+?\\){" section-fmt)) + (format (replace-match "\\1[%s]" nil nil section-fmt 1) + ;; Replace square brackets with parenthesis + ;; since square brackets are not supported in + ;; optional arguments. + (replace-regexp-in-string + "\\[" "(" (replace-regexp-in-string "\\]" ")" opt-title)) + full-text + (concat headline-label pre-blanks contents)) + ;; Impossible to add an alternative heading. Fallback to + ;; regular sectioning format string. + (format section-fmt full-text + (concat headline-label pre-blanks contents)))))))) + +(defun org-latex-format-headline-default-function + (todo _todo-type priority text tags _info) + "Default format function for a headline. +See `org-latex-format-headline-function' for details." + (concat + (and todo (format "{\\bfseries\\sffamily %s} " todo)) + (and priority (format "\\framebox{\\#%c} " priority)) + text + (and tags + (format "\\hfill{}\\textsc{%s}" + (mapconcat #'org-latex--protect-text tags ":"))))) + + +;;;; 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 (org-export-read-attribute :attr_latex horizontal-rule)) + (prev (org-export-get-previous-element horizontal-rule info))) + (concat + ;; Make sure the rule doesn't start at the end of the current + ;; line by separating it with a blank line from previous element. + (when (and prev + (let ((prev-blank (org-element-property :post-blank prev))) + (or (not prev-blank) (zerop prev-blank)))) + "\n") + (org-latex--wrap-label + horizontal-rule + (format "\\noindent\\rule{%s}{%s}" + (or (plist-get attr :width) "\\textwidth") + (or (plist-get attr :thickness) "0.5pt")) + info)))) + + +;;;; 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-property :value inline-src-block)) + (separator (org-latex--find-verb-separator code))) + (cl-case (plist-get info :latex-listings) + ;; Do not use a special package: transcode it verbatim, as code. + ((nil) (org-latex--text-markup code 'code info)) + ;; Use minted package. + (minted + (let* ((org-lang (org-element-property :language inline-src-block)) + (mint-lang (or (cadr (assq (intern org-lang) + (plist-get info :latex-minted-langs))) + (downcase org-lang))) + (options (org-latex--make-option-string + (plist-get info :latex-minted-options)))) + (format "\\mintinline%s{%s}{%s}" + (if (string= options "") "" (format "[%s]" options)) + mint-lang + code))) + ;; Use listings package. + (otherwise + ;; Maybe translate language's name. + (let* ((org-lang (org-element-property :language inline-src-block)) + (lst-lang (or (cadr (assq (intern org-lang) + (plist-get info :latex-listings-langs))) + org-lang)) + (options (org-latex--make-option-string + (append (plist-get info :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-data (org-element-property :title inlinetask) info)) + (todo (and (plist-get info :with-todo-keywords) + (let ((todo (org-element-property :todo-keyword inlinetask))) + (and todo (org-export-data todo info))))) + (todo-type (org-element-property :todo-type inlinetask)) + (tags (and (plist-get info :with-tags) + (org-export-get-tags inlinetask info))) + (priority (and (plist-get info :with-priority) + (org-element-property :priority inlinetask))) + (contents (concat (org-latex--label inlinetask info) contents))) + (funcall (plist-get info :latex-format-inlinetask-function) + todo todo-type priority title tags contents info))) + +(defun org-latex-format-inlinetask-default-function + (todo _todo-type priority title tags contents _info) + "Default format function for inlinetasks. +See `org-latex-format-inlinetask-function' for details." + (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}" + (org-make-tag-string + (mapcar #'org-latex--protect-text tags))))))) + (concat "\\begin{center}\n" + "\\fbox{\n" + "\\begin{minipage}[c]{.6\\textwidth}\n" + full-title "\n\n" + (and (org-string-nw-p contents) + (concat "\\rule[.8em]{\\textwidth}{2pt}\n\n" contents)) + "\\end{minipage}\n" + "}\n" + "\\end{center}"))) + + +;;;; Italic + +(defun org-latex-italic (_italic contents info) + "Transcode ITALIC from Org to LaTeX. +CONTENTS is the text with italic markup. INFO is a plist holding +contextual information." + (org-latex--text-markup contents 'italic info)) + + +;;;; 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* ((orderedp (eq (org-element-property + :type (org-export-get-parent item)) + 'ordered)) + (level + ;; Determine level of current item to determine the + ;; correct LaTeX counter to use (enumi, enumii...). + (let ((parent item) (level 0)) + (while (memq (org-element-type + (setq parent (org-export-get-parent parent))) + '(plain-list item)) + (when (and (eq (org-element-type parent) 'plain-list) + (eq (org-element-property :type parent) + 'ordered)) + (cl-incf level))) + level)) + (count (org-element-property :counter item)) + (counter (and count + (< level 5) + (format "\\setcounter{enum%s}{%s}\n" + (nth (1- level) '("i" "ii" "iii" "iv")) + (1- count)))) + (checkbox (cl-case (org-element-property :checkbox item) + (on "$\\boxtimes$") + (off "$\\square$") + (trans "$\\boxminus$"))) + (tag (let ((tag (org-element-property :tag item))) + (and tag (org-export-data tag info)))) + ;; If there are footnotes references in tag, be sure to add + ;; their definition at the end of the item. This workaround + ;; is necessary since "\footnote{}" command is not supported + ;; in tags. + (tag-footnotes + (or (and tag (org-latex--delayed-footnotes-definitions + (org-element-property :tag item) info)) + ""))) + (concat counter + "\\item" + (cond + ((and checkbox tag) + (format (if orderedp "{%s %s} %s" "[{%s %s}] %s") + checkbox tag tag-footnotes)) + ((or checkbox tag) + (format (if orderedp "{%s} %s" "[{%s}] %s") + (or checkbox tag) tag-footnotes)) + ;; Without a tag or a check-box, if CONTENTS starts with + ;; an opening square bracket, add "\relax" to "\item", + ;; unless the brackets comes from an initial export + ;; snippet (i.e. it is inserted willingly by the user). + ((and contents + (string-match-p "\\`[ \t]*\\[" contents) + (not (let ((e (car (org-element-contents item)))) + (and (eq (org-element-type e) 'paragraph) + (let ((o (car (org-element-contents e)))) + (and (eq (org-element-type o) 'export-snippet) + (eq (org-export-snippet-backend o) + 'latex))))))) + "\\relax ") + (t " ")) + (and contents (org-trim 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 (org-element-property :key keyword)) + (value (org-element-property :value keyword))) + (cond + ((string= key "LATEX") value) + ((string= key "INDEX") (format "\\index{%s}" value)) + ((string= key "TOC") + (let ((case-fold-search t)) + (cond + ((string-match-p "\\<headlines\\>" value) + (let* ((localp (string-match-p "\\<local\\>" value)) + (parent (org-element-lineage keyword '(headline))) + (level (if (not (and localp parent)) 0 + (org-export-get-relative-level parent info))) + (depth + (and (string-match "\\<[0-9]+\\>" value) + (format + "\\setcounter{tocdepth}{%d}" + (+ (string-to-number (match-string 0 value)) level))))) + (if (and localp parent) + ;; Start local TOC, assuming package "titletoc" is + ;; required. + (format "\\startcontents[level-%d] +\\printcontents[level-%d]{}{0}{%s}" + level level (or depth "")) + (concat depth (and depth "\n") "\\tableofcontents")))) + ((string-match-p "\\<tables\\>" value) "\\listoftables") + ((string-match-p "\\<listings\\>" value) + (cl-case (plist-get info :latex-listings) + ((nil) "\\listoffigures") + (minted "\\listoflistings") + (otherwise "\\lstlistoflistings"))))))))) + + +;;;; Latex Environment + +(defun org-latex--environment-type (latex-environment) + "Return the TYPE of LATEX-ENVIRONMENT. + +The TYPE is determined from the actual latex environment, and +could be a member of `org-latex-caption-above' or `math'." + (let* ((latex-begin-re "\\\\begin{\\([A-Za-z0-9*]+\\)}") + (value (org-remove-indentation + (org-element-property :value latex-environment))) + (env (or (and (string-match latex-begin-re value) + (match-string 1 value)) + ""))) + (cond + ((string-match-p org-latex-math-environments-re value) 'math) + ((string-match-p + (eval-when-compile + (regexp-opt '("table" "longtable" "tabular" "tabu" "longtabu"))) + env) + 'table) + ((string-match-p "figure" env) 'image) + ((string-match-p + (eval-when-compile + (regexp-opt '("lstlisting" "listing" "verbatim" "minted"))) + env) + 'src-block) + (t 'special-block)))) + +(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." + (when (plist-get info :with-latex) + (let* ((value (org-remove-indentation + (org-element-property :value latex-environment))) + (type (org-latex--environment-type latex-environment)) + (caption (if (eq type 'math) + (org-latex--label latex-environment info nil t) + (org-latex--caption/label-string latex-environment info))) + (caption-above-p + (memq type (append (plist-get info :latex-caption-above) '(math))))) + (if (not (or (org-element-property :name latex-environment) + (org-element-property :caption latex-environment))) + value + ;; Environment is labeled: label must be within the environment + ;; (otherwise, a reference pointing to that element will count + ;; the section instead). Also insert caption if `latex-environment' + ;; is not a math environment. + (with-temp-buffer + (insert value) + (if caption-above-p + (progn + (goto-char (point-min)) + (forward-line)) + (goto-char (point-max)) + (forward-line -1)) + (insert caption) + (buffer-string)))))) + +;;;; 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." + (let ((value (org-element-property :value latex-fragment))) + ;; Trim math markers since the fragment is enclosed within + ;; a latex-math-block object anyway. + (cond ((string-match-p "\\`\\$[^$]" value) (substring value 1 -1)) + ((string-prefix-p "\\(" value) (substring value 2 -2)) + (t value)))) + + +;;;; 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." + "\\\\\n") + + +;;;; Link + +(defun org-latex-image-link-filter (data _backend info) + (org-export-insert-image-links data info org-latex-inline-image-rules)) + +(defun org-latex--inline-image (link info) + "Return LaTeX code for an inline image. +LINK is the link pointing to the inline image. INFO is a plist +used as a communication channel." + (let* ((parent (org-export-get-parent-element link)) + (path (let ((raw-path (org-element-property :path link))) + (if (not (file-name-absolute-p raw-path)) raw-path + (expand-file-name raw-path)))) + (filetype (file-name-extension path)) + (caption (org-latex--caption/label-string parent info)) + (caption-above-p (org-latex--caption-above-p link info)) + ;; Retrieve latex attributes from the element around. + (attr (org-export-read-attribute :attr_latex parent)) + (float (let ((float (plist-get attr :float))) + (cond ((string= float "wrap") 'wrap) + ((string= float "sideways") 'sideways) + ((string= float "multicolumn") 'multicolumn) + ((and (plist-member attr :float) (not float)) 'nonfloat) + (float float) + ((or (org-element-property :caption parent) + (org-string-nw-p (plist-get attr :caption))) + 'figure) + (t 'nonfloat)))) + (placement + (let ((place (plist-get attr :placement))) + (cond + (place (format "%s" place)) + ((eq float 'wrap) "{l}{0.5\\textwidth}") + ((eq float 'figure) + (format "[%s]" (plist-get info :latex-default-figure-position))) + (t "")))) + (center + (cond + ;; If link is an image link, do not center. + ((eq 'link (org-element-type (org-export-get-parent link))) nil) + ((plist-member attr :center) (plist-get attr :center)) + (t (plist-get info :latex-images-centered)))) + (comment-include (if (plist-get attr :comment-include) "%" "")) + ;; It is possible to specify scale or width and height in + ;; the ATTR_LATEX line, and also via default variables. + (scale (cond ((eq float 'wrap) "") + ((plist-get attr :scale)) + (t (plist-get info :latex-image-default-scale)))) + (width (cond ((org-string-nw-p scale) "") + ((plist-get attr :width)) + ((plist-get attr :height) "") + ((eq float 'wrap) "0.48\\textwidth") + (t (plist-get info :latex-image-default-width)))) + (height (cond ((org-string-nw-p scale) "") + ((plist-get attr :height)) + ((or (plist-get attr :width) + (memq float '(figure wrap))) "") + (t (plist-get info :latex-image-default-height)))) + (options (let ((opt (or (plist-get attr :options) + (plist-get info :latex-image-default-option)))) + (if (not (string-match "\\`\\[\\(.*\\)\\]\\'" opt)) opt + (match-string 1 opt)))) + image-code) + (if (member filetype '("tikz" "pgf")) + ;; For tikz images: + ;; - use \input to read in image file. + ;; - if options are present, wrap in a tikzpicture environment. + ;; - if width or height are present, use \resizebox to change + ;; the image size. + (progn + (setq image-code (format "\\input{%s}" path)) + (when (org-string-nw-p options) + (setq image-code + (format "\\begin{tikzpicture}[%s]\n%s\n\\end{tikzpicture}" + options + image-code))) + (setq image-code + (cond ((org-string-nw-p scale) + (format "\\scalebox{%s}{%s}" scale image-code)) + ((or (org-string-nw-p width) (org-string-nw-p height)) + (format "\\resizebox{%s}{%s}{%s}" + (if (org-string-nw-p width) width "!") + (if (org-string-nw-p height) height "!") + image-code)) + (t image-code)))) + ;; For other images: + ;; - add scale, or width and height to options. + ;; - include the image with \includegraphics. + (if (org-string-nw-p scale) + (setq options (concat options ",scale=" scale)) + (when (org-string-nw-p width) (setq options (concat options ",width=" width))) + (when (org-string-nw-p height) (setq options (concat options ",height=" height)))) + (let ((search-option (org-element-property :search-option link))) + (when (and search-option + (equal filetype "pdf") + (string-match-p "\\`[0-9]+\\'" search-option) + (not (string-match-p "page=" options))) + (setq options (concat options ",page=" search-option)))) + (setq image-code + (format "\\includegraphics%s{%s}" + (cond ((not (org-string-nw-p options)) "") + ((string-prefix-p "," options) + (format "[%s]" (substring options 1))) + (t (format "[%s]" options))) + path)) + (when (equal filetype "svg") + (setq image-code (replace-regexp-in-string "^\\\\includegraphics" + "\\includesvg" + image-code + nil t)) + (setq image-code (replace-regexp-in-string "\\.svg}" + "}" + image-code + nil t)))) + ;; Return proper string, depending on FLOAT. + (pcase float + ((and (pred stringp) env-string) + (format "\\begin{%s}%s +%s%s +%s%s +%s\\end{%s}" + env-string + placement + (if caption-above-p caption "") + (if center "\\centering" "") + comment-include image-code + (if caption-above-p "" caption) + env-string)) + (`wrap (format "\\begin{wrapfigure}%s +%s%s +%s%s +%s\\end{wrapfigure}" + placement + (if caption-above-p caption "") + (if center "\\centering" "") + comment-include image-code + (if caption-above-p "" caption))) + (`sideways (format "\\begin{sidewaysfigure} +%s%s +%s%s +%s\\end{sidewaysfigure}" + (if caption-above-p caption "") + (if center "\\centering" "") + comment-include image-code + (if caption-above-p "" caption))) + (`multicolumn (format "\\begin{figure*}%s +%s%s +%s%s +%s\\end{figure*}" + placement + (if caption-above-p caption "") + (if center "\\centering" "") + comment-include image-code + (if caption-above-p "" caption))) + (`figure (format "\\begin{figure}%s +%s%s +%s%s +%s\\end{figure}" + placement + (if caption-above-p caption "") + (if center "\\centering" "") + comment-include image-code + (if caption-above-p "" caption))) + ((guard center) + (format "\\begin{center} +%s%s +%s\\end{center}" + (if caption-above-p caption "") + image-code + (if caption-above-p "" caption))) + (_ + (concat (if caption-above-p caption "") + image-code + (if caption-above-p caption "")))))) + +(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-property :type link)) + (raw-path (org-element-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 (plist-get info :latex-inline-image-rules))) + (path (org-latex--protect-text + (pcase type + ((or "http" "https" "ftp" "mailto" "doi") + (concat type ":" raw-path)) + ("file" + (org-export-file-uri raw-path)) + (_ + raw-path))))) + (cond + ;; Link type is handled by a special function. + ((org-export-custom-protocol-maybe link desc 'latex info)) + ;; Image file. + (imagep (org-latex--inline-image link info)) + ;; Radio link: Transcode target's contents and use them as link's + ;; description. + ((string= type "radio") + (let ((destination (org-export-resolve-radio-link link info))) + (if (not destination) desc + (format "\\hyperref[%s]{%s}" + (org-export-get-reference destination info) + desc)))) + ;; Links pointing to a headline: Find destination and build + ;; appropriate referencing command. + ((member type '("custom-id" "fuzzy" "id")) + (let ((destination + (if (string= type "fuzzy") + (org-export-resolve-fuzzy-link link info 'latex-matrices) + (org-export-resolve-id-link link info)))) + (cl-case (org-element-type destination) + ;; Id link points to an external file. + (plain-text + (if desc (format "\\href{%s}{%s}" destination desc) + (format "\\url{%s}" destination))) + ;; Fuzzy link points nowhere. + ((nil) + (format (plist-get info :latex-link-with-unknown-path-format) + (or desc + (org-export-data + (org-element-property :raw-link link) info)))) + ;; LINK points to a headline. If headlines are numbered + ;; and the link has no description, display headline's + ;; number. Otherwise, display description or headline's + ;; title. + (headline + (let ((label (org-latex--label destination info t))) + (if (and (not desc) + (org-export-numbered-headline-p destination info)) + (format org-latex-reference-command label) + (format "\\hyperref[%s]{%s}" label + (or desc + (org-export-data + (org-element-property :title destination) info)))))) + ;; Fuzzy link points to a target. Do as above. + (otherwise + (let ((ref (org-latex--label destination info t))) + (if (not desc) (format org-latex-reference-command ref) + (format "\\hyperref[%s]{%s}" ref desc))))))) + ;; Coderef: replace link with the reference name or the + ;; equivalent line number. + ((string= type "coderef") + (format (org-export-get-coderef-format path desc) + ;; Resolve with RAW-PATH since PATH could be tainted + ;; with `org-latex--protect-text' call above. + (org-export-resolve-coderef raw-path info))) + ;; 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 (plist-get info :latex-link-with-unknown-path-format) desc))))) + + +;;;; Node Property + +(defun org-latex-node-property (node-property _contents _info) + "Transcode a NODE-PROPERTY element from Org to LaTeX. +CONTENTS is nil. INFO is a plist holding contextual +information." + (format "%s:%s" + (org-element-property :key node-property) + (let ((value (org-element-property :value node-property))) + (if value (concat " " value) "")))) + + +;;;; 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-property :type plain-list)) + (attr (org-export-read-attribute :attr_latex plain-list)) + (latex-type (let ((env (plist-get attr :environment))) + (cond (env (format "%s" env)) + ((eq type 'ordered) "enumerate") + ((eq type 'descriptive) "description") + (t "itemize"))))) + (org-latex--wrap-label + plain-list + (format "\\begin{%s}%s\n%s\\end{%s}" + latex-type + (or (plist-get attr :options) "") + contents + latex-type) + info))) + + +;;;; 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." + (let* ((specialp (plist-get info :with-special-strings)) + (output + ;; Turn LaTeX into \LaTeX{} and TeX into \TeX{}. + (let ((case-fold-search nil)) + (replace-regexp-in-string + "\\<\\(?:La\\)?TeX\\>" "\\\\\\&{}" + ;; Protect ^, ~, %, #, &, $, _, { and }. Also protect \. + ;; However, if special strings are used, be careful not + ;; to protect "\" in "\-" constructs. + (replace-regexp-in-string + (concat "[%$#&{}_~^]\\|\\\\" (and specialp "\\([^-]\\|$\\)")) + (lambda (m) + (cl-case (string-to-char m) + (?\\ "$\\\\backslash$\\1") + (?~ "\\\\textasciitilde{}") + (?^ "\\\\^{}") + (t "\\\\\\&"))) + text))))) + ;; Activate smart quotes. Be sure to provide original TEXT string + ;; since OUTPUT may have been modified. + (when (plist-get info :with-smart-quotes) + (setq output (org-export-activate-smart-quotes output :latex info text))) + ;; Convert special strings. + (when specialp + (setq output (replace-regexp-in-string "\\.\\.\\." "\\\\ldots{}" output))) + ;; Handle break preservation if required. + (when (plist-get info :preserve-breaks) + (setq output (replace-regexp-in-string + "\\(?:[ \t]*\\\\\\\\\\)?[ \t]*\n" "\\\\\n" output nil t))) + ;; Return value. + output)) + + +;;;; Planning + +(defun org-latex-planning (planning _contents info) + "Transcode a PLANNING element from Org to LaTeX. +CONTENTS is nil. INFO is a plist holding contextual +information." + (concat + "\\noindent" + (mapconcat + 'identity + (delq nil + (list + (let ((closed (org-element-property :closed planning))) + (when closed + (concat + (format "\\textbf{%s} " org-closed-string) + (format (plist-get info :latex-inactive-timestamp-format) + (org-timestamp-translate closed))))) + (let ((deadline (org-element-property :deadline planning))) + (when deadline + (concat + (format "\\textbf{%s} " org-deadline-string) + (format (plist-get info :latex-active-timestamp-format) + (org-timestamp-translate deadline))))) + (let ((scheduled (org-element-property :scheduled planning))) + (when scheduled + (concat + (format "\\textbf{%s} " org-scheduled-string) + (format (plist-get info :latex-active-timestamp-format) + (org-timestamp-translate scheduled))))))) + " ") + "\\\\")) + + +;;;; Property Drawer + +(defun org-latex-property-drawer (_property-drawer contents _info) + "Transcode a PROPERTY-DRAWER element from Org to LaTeX. +CONTENTS holds the contents of the drawer. INFO is a plist +holding contextual information." + (and (org-string-nw-p contents) + (format "\\begin{verbatim}\n%s\\end{verbatim}" contents))) + + +;;;; Pseudo Element: LaTeX Matrices + +;; `latex-matrices' elements have the following properties: +;; `:caption', `:post-blank' and `:markup' (`inline', `equation' or +;; `math'). + +(defun org-latex--wrap-latex-matrices (data info) + "Merge contiguous tables with the same mode within a pseudo-element. +DATA is a parse tree or a secondary string. INFO is a plist +containing export options. Modify DATA by side-effect and return +it." + (org-element-map data 'table + (lambda (table) + (when (eq (org-element-property :type table) 'org) + (let ((mode (or (org-export-read-attribute :attr_latex table :mode) + (plist-get info :latex-default-table-mode)))) + (when (and (member mode '("inline-math" "math")) + ;; Do not wrap twice the same table. + (not (eq (org-element-type + (org-element-property :parent table)) + 'latex-matrices))) + (let* ((caption (and (not (string= mode "inline-math")) + (org-element-property :caption table))) + (name (and (not (string= mode "inline-math")) + (org-element-property :name table))) + (matrices + (list 'latex-matrices + ;; Inherit name from the first table. + (list :name name + ;; FIXME: what syntax for captions? + ;; + ;; :caption caption + :markup + (cond ((string= mode "inline-math") 'inline) + ((or caption name) 'equation) + (t 'math))))) + (previous table) + (next (org-export-get-next-element table info))) + (org-element-insert-before matrices table) + ;; Swallow all contiguous tables sharing the same mode. + (while (and + (zerop (or (org-element-property :post-blank previous) 0)) + (setq next (org-export-get-next-element previous info)) + (eq (org-element-type next) 'table) + (eq (org-element-property :type next) 'org) + (string= (or (org-export-read-attribute + :attr_latex next :mode) + (plist-get info :latex-default-table-mode)) + mode)) + (org-element-put-property table :name nil) + (org-element-put-property table :caption nil) + (org-element-extract-element previous) + (org-element-adopt-elements matrices previous) + (setq previous next)) + ;; Inherit `:post-blank' from the value of the last + ;; swallowed table. Set the latter's `:post-blank' + ;; value to 0 so as to not duplicate empty lines. + (org-element-put-property + matrices :post-blank (org-element-property :post-blank previous)) + (org-element-put-property previous :post-blank 0) + (org-element-put-property table :name nil) + (org-element-put-property table :caption nil) + (org-element-extract-element previous) + (org-element-adopt-elements matrices previous)))))) + info) + data) + +(defun org-latex-matrices (matrices contents info) + "Transcode a MATRICES element from Org to LaTeX. +CONTENTS is a string. INFO is a plist used as a communication +channel." + (pcase (org-element-property :markup matrices) + (`inline (format "\\(%s\\)" contents)) + (`equation + (let ((caption (org-latex--caption/label-string matrices info)) + (caption-above? (org-latex--caption-above-p matrices info))) + (concat "\\begin{equation}\n" + (and caption-above? caption) + contents + (and (not caption-above?) caption) + "\\end{equation}"))) + (_ + (format "\\[\n%s\\]" contents)))) + + +;;;; Pseudo Object: LaTeX Math Block + +;; `latex-math-block' objects have the following property: +;; `:post-blank'. + +(defun org-latex--wrap-latex-math-block (data info) + "Merge contiguous math objects in a pseudo-object container. +DATA is a parse tree or a secondary string. INFO is a plist +containing export options. Modify DATA by side-effect and return it." + (let ((valid-object-p + ;; Non-nil when OBJECT can be added to a latex math block. + (lambda (object) + (pcase (org-element-type object) + (`entity (org-element-property :latex-math-p object)) + (`latex-fragment + (let ((value (org-element-property :value object))) + (or (string-prefix-p "\\(" value) + (string-match-p "\\`\\$[^$]" value)))))))) + (org-element-map data '(entity latex-fragment) + (lambda (object) + ;; Skip objects already wrapped. + (when (and (not (eq (org-element-type + (org-element-property :parent object)) + 'latex-math-block)) + (funcall valid-object-p object)) + (let ((math-block (list 'latex-math-block nil)) + (next-elements (org-export-get-next-element object info t)) + (last object)) + ;; Wrap MATH-BLOCK around OBJECT in DATA. + (org-element-insert-before math-block object) + (org-element-extract-element object) + (org-element-adopt-elements math-block object) + (when (zerop (or (org-element-property :post-blank object) 0)) + ;; MATH-BLOCK swallows consecutive math objects. + (catch 'exit + (dolist (next next-elements) + (unless (funcall valid-object-p next) (throw 'exit nil)) + (org-element-extract-element next) + (org-element-adopt-elements math-block next) + ;; Eschew the case: \beta$x$ -> \(\betax\). + (org-element-put-property last :post-blank 1) + (setq last next) + (when (> (or (org-element-property :post-blank next) 0) 0) + (throw 'exit nil))))) + (org-element-put-property + math-block :post-blank (org-element-property :post-blank last))))) + info nil '(latex-math-block) t) + ;; Return updated DATA. + data)) + +(defun org-latex-math-block (_math-block contents _info) + "Transcode a MATH-BLOCK object from Org to LaTeX. +CONTENTS is a string. INFO is a plist used as a communication +channel." + (when (org-string-nw-p contents) + (format "\\(%s\\)" (org-trim contents)))) + +;;;; 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." + (let ((environment + (or (org-export-read-attribute :attr_latex quote-block :environment) + (plist-get info :latex-default-quote-environment))) + (options + (or (org-export-read-attribute :attr_latex quote-block :options) + ""))) + (org-latex--wrap-label + quote-block (format "\\begin{%s}%s\n%s\\end{%s}" + environment + options + contents + environment) + info))) + +;;;; 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-get-reference radio-target info) text)) + + +;;;; Section + +(defun org-latex-section (_section contents _info) + "Transcode a SECTION element from Org to LaTeX. +CONTENTS holds the contents of the section. INFO is a plist +holding contextual information." + contents) + + +;;;; 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 (org-element-property :type special-block)) + (opt (org-export-read-attribute :attr_latex special-block :options)) + (caption (org-latex--caption/label-string special-block info)) + (caption-above-p (org-latex--caption-above-p special-block info))) + (concat (format "\\begin{%s}%s\n" type (or opt "")) + (and caption-above-p caption) + contents + (and (not caption-above-p) caption) + (format "\\end{%s}" 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." + (when (org-string-nw-p (org-element-property :value src-block)) + (let* ((lang (org-element-property :language src-block)) + (caption (org-element-property :caption src-block)) + (caption-above-p (org-latex--caption-above-p src-block info)) + (label (org-element-property :name src-block)) + (custom-env (and lang + (cadr (assq (intern lang) + org-latex-custom-lang-environments)))) + (num-start (org-export-get-loc src-block info)) + (retain-labels (org-element-property :retain-labels src-block)) + (attributes (org-export-read-attribute :attr_latex src-block)) + (float (plist-get attributes :float)) + (listings (plist-get info :latex-listings))) + (cond + ;; Case 1. No source fontification. + ((or (not lang) (not listings)) + (let ((caption-str (org-latex--caption/label-string src-block info)) + (verbatim (format "\\begin{verbatim}\n%s\\end{verbatim}" + (org-export-format-code-default src-block info)))) + (cond ((string= "multicolumn" float) + (format "\\begin{figure*}[%s]\n%s%s\n%s\\end{figure*}" + (plist-get info :latex-default-figure-position) + (if caption-above-p caption-str "") + verbatim + (if caption-above-p "" caption-str))) + (caption (concat + (if caption-above-p caption-str "") + verbatim + (if caption-above-p "" (concat "\n" caption-str)))) + (t verbatim)))) + ;; Case 2. Custom environment. + (custom-env + (let ((caption-str (org-latex--caption/label-string src-block info)) + (formatted-src (org-export-format-code-default src-block info))) + (if (string-match-p "\\`[a-zA-Z0-9]+\\'" custom-env) + (format "\\begin{%s}\n%s\\end{%s}\n" + custom-env + (concat (and caption-above-p caption-str) + formatted-src + (and (not caption-above-p) caption-str)) + custom-env) + (format-spec custom-env + `((?s . ,formatted-src) + (?c . ,caption) + (?f . ,float) + (?l . ,(org-latex--label src-block info)) + (?o . ,(or (plist-get attributes :options) ""))))))) + ;; Case 3. Use minted package. + ((eq listings 'minted) + (let* ((caption-str (org-latex--caption/label-string src-block info)) + (placement (or (org-unbracket-string "[" "]" (plist-get attributes :placement)) + (plist-get info :latex-default-figure-position))) + (float-env + (cond + ((string= "multicolumn" float) + (format "\\begin{listing*}[%s]\n%s%%s\n%s\\end{listing*}" + placement + (if caption-above-p caption-str "") + (if caption-above-p "" caption-str))) + (caption + (format "\\begin{listing}[%s]\n%s%%s\n%s\\end{listing}" + placement + (if caption-above-p caption-str "") + (if caption-above-p "" caption-str))) + ((string= "t" float) + (concat (format "\\begin{listing}[%s]\n" + placement) + "%s\n\\end{listing}")) + (t "%s"))) + (options (plist-get info :latex-minted-options)) + (body + (format + "\\begin{minted}[%s]{%s}\n%s\\end{minted}" + ;; Options. + (concat + (org-latex--make-option-string + (if (or (not num-start) (assoc "linenos" options)) + options + (append + `(("linenos") + ("firstnumber" ,(number-to-string (1+ num-start)))) + options))) + (let ((local-options (plist-get attributes :options))) + (and local-options (concat "," local-options)))) + ;; Language. + (or (cadr (assq (intern lang) + (plist-get info :latex-minted-langs))) + (downcase lang)) + ;; Source code. + (let* ((code-info (org-export-unravel-code src-block)) + (max-width + (apply 'max + (mapcar 'length + (org-split-string (car code-info) + "\n"))))) + (org-export-format-code + (car code-info) + (lambda (loc _num ref) + (concat + loc + (when ref + ;; Ensure references are flushed to the right, + ;; separated with 6 spaces from the widest line + ;; of code. + (concat (make-string (+ (- max-width (length loc)) 6) + ?\s) + (format "(%s)" ref))))) + nil (and retain-labels (cdr code-info))))))) + ;; Return value. + (format float-env body))) + ;; Case 4. Use listings package. + (t + (let ((lst-lang + (or (cadr (assq (intern lang) + (plist-get info :latex-listings-langs))) + lang)) + (caption-str + (when caption + (let ((main (org-export-get-caption src-block)) + (secondary (org-export-get-caption src-block t))) + (if (not secondary) + (format "{%s}" (org-export-data main info)) + (format "{[%s]%s}" + (org-export-data secondary info) + (org-export-data main info)))))) + (lst-opt (plist-get info :latex-listings-options))) + (concat + ;; Options. + (format + "\\lstset{%s}\n" + (concat + (org-latex--make-option-string + (append + lst-opt + (cond + ((and (not float) (plist-member attributes :float)) nil) + ((string= "multicolumn" float) '(("float" "*"))) + ((and float (not (assoc "float" lst-opt))) + `(("float" ,(plist-get info :latex-default-figure-position))))) + `(("language" ,lst-lang)) + (if label + `(("label" ,(org-latex--label src-block info))) + '(("label" " "))) + (if caption-str `(("caption" ,caption-str)) '(("caption" " "))) + `(("captionpos" ,(if caption-above-p "t" "b"))) + (cond ((assoc "numbers" lst-opt) nil) + ((not num-start) '(("numbers" "none"))) + (t `(("firstnumber" ,(number-to-string (1+ num-start))) + ("numbers" "left")))))) + (let ((local-options (plist-get attributes :options))) + (and local-options (concat "," local-options))))) + ;; Source code. + (format + "\\begin{lstlisting}\n%s\\end{lstlisting}" + (let* ((code-info (org-export-unravel-code src-block)) + (max-width + (apply 'max + (mapcar 'length + (org-split-string (car code-info) "\n"))))) + (org-export-format-code + (car code-info) + (lambda (loc _num ref) + (concat + loc + (when ref + ;; Ensure references are flushed to the right, + ;; separated with 6 spaces from the widest line of + ;; code + (concat (make-string (+ (- max-width (length loc)) 6) ?\s) + (format "(%s)" ref))))) + nil (and retain-labels (cdr code-info)))))))))))) + + +;;;; 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." + (replace-regexp-in-string + "%" "\\%" (org-element-property :value statistics-cookie) nil t)) + + +;;;; Strike-Through + +(defun org-latex-strike-through (_strike-through contents info) + "Transcode STRIKE-THROUGH from Org to LaTeX. +CONTENTS is the text with strike-through markup. INFO is a plist +holding contextual information." + (org-latex--text-markup contents 'strike-through info)) + + +;;;; Subscript + +(defun org-latex-subscript (_subscript contents _info) + "Transcode a SUBSCRIPT object from Org to LaTeX. +CONTENTS is the contents of the object." + (format "\\textsubscript{%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." + (format "\\textsuperscript{%s}" contents)) + + +;;;; Table +;; +;; `org-latex-table' is the entry point for table transcoding. It +;; takes care of tables with a "verbatim" mode. Otherwise, it +;; delegates the job to either `org-latex--table.el-table', +;; `org-latex--org-table' or `org-latex--math-table' functions, +;; depending of the type of the table and the mode requested. +;; +;; `org-latex--align-string' is a subroutine used to build alignment +;; string for Org tables. + +(defun org-latex-table (table contents info) + "Transcode a TABLE element from Org to LaTeX. +CONTENTS is the contents of the table. INFO is a plist holding +contextual information." + (if (eq (org-element-property :type table) 'table.el) + ;; "table.el" table. Convert it using appropriate tools. + (org-latex--table.el-table table info) + (let ((type (or (org-export-read-attribute :attr_latex table :mode) + (plist-get info :latex-default-table-mode)))) + (cond + ;; Case 1: Verbatim table. + ((string= type "verbatim") + (format "\\begin{verbatim}\n%s\n\\end{verbatim}" + ;; Re-create table, without affiliated keywords. + (org-trim (org-element-interpret-data + `(table nil ,@(org-element-contents table)))))) + ;; Case 2: Matrix. + ((or (string= type "math") (string= type "inline-math")) + (org-latex--math-table table info)) + ;; Case 3: Standard table. + (t (concat (org-latex--org-table table contents info) + ;; When there are footnote references within the + ;; table, insert their definition just after it. + (org-latex--delayed-footnotes-definitions table info))))))) + +(defun org-latex--align-string (table info &optional math?) + "Return an appropriate LaTeX alignment string. +TABLE is the considered table. INFO is a plist used as +a communication channel. When optional argument MATH? is +non-nil, TABLE is meant to be a matrix, where all cells are +centered." + (or (org-export-read-attribute :attr_latex table :align) + (let (align) + ;; Extract column groups and alignment from first (non-rule) + ;; row. + (org-element-map + (org-element-map table 'table-row + (lambda (row) + (and (eq (org-element-property :type row) 'standard) row)) + info 'first-match) + 'table-cell + (lambda (cell) + (let ((borders (org-export-table-cell-borders cell info))) + ;; Check left border for the first cell only. + (when (and (memq 'left borders) (not align)) + (push "|" align)) + (push (if math? "c" ;center cells in matrices + (cl-case (org-export-table-cell-alignment cell info) + (left "l") + (right "r") + (center "c"))) + align) + (when (memq 'right borders) (push "|" align)))) + info) + (apply 'concat (nreverse align))))) + +(defun org-latex--decorate-table (table attributes caption above? info) + "Decorate TABLE string with caption and float environment. + +ATTRIBUTES is the plist containing LaTeX attributes. CAPTION is +its caption, as a string or nil. It is located above the table +if ABOVE? is non-nil. INFO is the plist containing current +export parameters. + +Return new environment, as a string." + (let* ((float-environment + (let ((float (plist-get attributes :float))) + (cond ((and (not float) (plist-member attributes :float)) nil) + ((member float '("sidewaystable" "sideways")) "sidewaystable") + ((equal float "multicolumn") "table*") + (float float) + ((org-string-nw-p caption) "table") + (t nil)))) + (placement + (or (plist-get attributes :placement) + (format "[%s]" (plist-get info :latex-default-figure-position)))) + (center? (if (plist-member attributes :center) + (plist-get attributes :center) + (plist-get info :latex-tables-centered))) + (fontsize (let ((font (plist-get attributes :font))) + (and font (concat font "\n"))))) + (concat (cond + (float-environment + (concat (format "\\begin{%s}%s\n" float-environment placement) + (if above? caption "") + (when center? "\\centering\n") + fontsize)) + (caption + (concat (and center? "\\begin{center}\n" ) + (if above? caption "") + (cond ((and fontsize center?) fontsize) + (fontsize (concat "{" fontsize)) + (t nil)))) + (center? (concat "\\begin{center}\n" fontsize)) + (fontsize (concat "{" fontsize))) + table + (cond + (float-environment + (concat (if above? "" (concat "\n" caption)) + (format "\n\\end{%s}" float-environment))) + (caption + (concat (if above? "" (concat "\n" caption)) + (and center? "\n\\end{center}") + (and fontsize (not center?) "}"))) + (center? "\n\\end{center}") + (fontsize "}"))))) + +(defun org-latex--org-table (table contents info) + "Return appropriate LaTeX code for an Org table. + +TABLE is the table type element to transcode. CONTENTS is its +contents, as a string. INFO is a plist used as a communication +channel. + +This function assumes TABLE has `org' as its `:type' property and +`table' as its `:mode' attribute." + (let* ((attr (org-export-read-attribute :attr_latex table)) + (alignment (org-latex--align-string table info)) + (table-env (or (plist-get attr :environment) + (plist-get info :latex-default-table-environment))) + (width + (let ((w (plist-get attr :width))) + (cond ((not w) "") + ((member table-env '("tabular" "longtable")) "") + ((member table-env '("tabu" "longtabu")) + (format (if (plist-get attr :spread) " spread %s " + " to %s ") + w)) + (t (format "{%s}" w))))) + (caption (org-latex--caption/label-string table info)) + (above? (org-latex--caption-above-p table info))) + (cond + ((member table-env '("longtable" "longtabu")) + (let ((fontsize (let ((font (plist-get attr :font))) + (and font (concat font "\n"))))) + (concat (and fontsize (concat "{" fontsize)) + (format "\\begin{%s}%s{%s}\n" table-env width alignment) + (and above? + (org-string-nw-p caption) + (concat caption "\\\\\n")) + contents + (and (not above?) + (org-string-nw-p caption) + (concat caption "\\\\\n")) + (format "\\end{%s}" table-env) + (and fontsize "}")))) + (t + (let ((output (format "\\begin{%s}%s{%s}\n%s\\end{%s}" + table-env + width + alignment + contents + table-env))) + (org-latex--decorate-table output attr caption above? info)))))) + +(defun org-latex--table.el-table (table info) + "Return appropriate LaTeX code for a table.el table. + +TABLE is the table type element to transcode. INFO is a plist +used as a communication channel. + +This function assumes TABLE has `table.el' as its `:type' +property." + (require 'table) + ;; Ensure "*org-export-table*" buffer is empty. + (with-current-buffer (get-buffer-create "*org-export-table*") + (erase-buffer)) + (let ((output + (replace-regexp-in-string + "^%.*\n" "" ;remove comments + (with-temp-buffer + (save-excursion (insert (org-element-property :value table))) + (re-search-forward "^[ \t]*|[^|]" nil t) + (table-generate-source 'latex "*org-export-table*") + (with-current-buffer "*org-export-table*" + (org-trim (buffer-string)))) + t t))) + (kill-buffer (get-buffer "*org-export-table*")) + (let ((attr (org-export-read-attribute :attr_latex table)) + (caption (org-latex--caption/label-string table info)) + (above? (org-latex--caption-above-p table info))) + (when (plist-get attr :rmlines) + ;; When the "rmlines" attribute is provided, remove all hlines + ;; but the one separating heading from the table body. + (let ((n 0) (pos 0)) + (while (and (< (length output) pos) + (setq pos (string-match "^\\\\hline\n?" output pos))) + (cl-incf n) + (unless (= n 2) (setq output (replace-match "" nil nil output)))))) + (org-latex--decorate-table output attr caption above? info)))) + +(defun org-latex--math-table (table info) + "Return appropriate LaTeX code for a matrix. + +TABLE is the table type element to transcode. INFO is a plist +used as a communication channel. + +This function assumes TABLE has `org' as its `:type' property and +`inline-math' or `math' as its `:mode' attribute." + (let* ((attr (org-export-read-attribute :attr_latex table)) + (env (or (plist-get attr :environment) + (plist-get info :latex-default-table-environment))) + (contents + (mapconcat + (lambda (row) + (if (eq (org-element-property :type row) 'rule) "\\hline" + ;; Return each cell unmodified. + (concat + (mapconcat + (lambda (cell) + (substring (org-element-interpret-data cell) 0 -1)) + (org-element-map row 'table-cell #'identity info) "&") + (or (cdr (assoc env org-latex-table-matrix-macros)) "\\\\") + "\n"))) + (org-element-map table 'table-row #'identity info) ""))) + (concat + ;; Prefix. + (plist-get attr :math-prefix) + ;; Environment. Also treat special cases. + (cond ((member env '("array" "tabular")) + (format "\\begin{%s}{%s}\n%s\\end{%s}" + env (org-latex--align-string table info t) contents env)) + ((assoc env org-latex-table-matrix-macros) + (format "\\%s%s{\n%s}" + env + (or (plist-get attr :math-arguments) "") + contents)) + (t (format "\\begin{%s}\n%s\\end{%s}" env contents env))) + ;; Suffix. + (plist-get attr :math-suffix)))) + + +;;;; Table Cell + +(defun org-latex-table-cell (table-cell contents info) + "Transcode a TABLE-CELL element from Org to LaTeX. +CONTENTS is the cell contents. INFO is a plist used as +a communication channel." + (concat + (let ((scientific-format (plist-get info :latex-table-scientific-notation))) + (if (and contents + scientific-format + (string-match orgtbl-exp-regexp contents)) + ;; Use appropriate format string for scientific + ;; notation. + (format scientific-format + (match-string 1 contents) + (match-string 2 contents)) + contents)) + (when (org-export-get-next-element table-cell info) " & "))) + + +;;;; Table Row + +(defun org-latex-table-row (table-row contents info) + "Transcode a TABLE-ROW element from Org to LaTeX. +CONTENTS is the contents of the row. INFO is a plist used as +a communication channel." + (let* ((attr (org-export-read-attribute :attr_latex + (org-export-get-parent table-row))) + (booktabsp (if (plist-member attr :booktabs) (plist-get attr :booktabs) + (plist-get info :latex-tables-booktabs))) + (longtablep + (member (or (plist-get attr :environment) + (plist-get info :latex-default-table-environment)) + '("longtable" "longtabu")))) + (if (eq (org-element-property :type table-row) 'rule) + (cond + ((not booktabsp) "\\hline") + ((not (org-export-get-previous-element table-row info)) "\\toprule") + ((not (org-export-get-next-element table-row info)) "\\bottomrule") + ((and longtablep + (org-export-table-row-ends-header-p + (org-export-get-previous-element table-row info) info)) + "") + (t "\\midrule")) + (concat + ;; When BOOKTABS are activated enforce top-rule even when no + ;; hline was specifically marked. + (and booktabsp (not (org-export-get-previous-element table-row info)) + "\\toprule\n") + contents "\\\\\n" + (cond + ;; Special case for long tables. Define header and footers. + ((and longtablep (org-export-table-row-ends-header-p table-row info)) + (let ((columns (cdr (org-export-table-dimensions + (org-export-get-parent-table table-row) info)))) + (format "%s +\\endfirsthead +\\multicolumn{%d}{l}{%s} \\\\ +%s +%s \\\\\n +%s +\\endhead +%s\\multicolumn{%d}{r}{%s} \\\\ +\\endfoot +\\endlastfoot" + (if booktabsp "\\midrule" "\\hline") + columns + (org-latex--translate "Continued from previous page" info) + (cond + ((not (org-export-table-row-starts-header-p table-row info)) + "") + (booktabsp "\\toprule\n") + (t "\\hline\n")) + contents + (if booktabsp "\\midrule" "\\hline") + (if booktabsp "\\midrule" "\\hline") + columns + (org-latex--translate "Continued on next page" info)))) + ;; When BOOKTABS are activated enforce bottom rule even when + ;; no hline was specifically marked. + ((and booktabsp (not (org-export-get-next-element table-row info))) + "\\bottomrule")))))) + + +;;;; Target + +(defun org-latex-target (target _contents info) + "Transcode a TARGET object from Org to LaTeX. +CONTENTS is nil. INFO is a plist holding contextual +information." + (format "\\label{%s}" (org-latex--label target info))) + + +;;;; Timestamp + +(defun org-latex-timestamp (timestamp _contents info) + "Transcode a TIMESTAMP object from Org to LaTeX. +CONTENTS is nil. INFO is a plist holding contextual +information." + (let ((value (org-latex-plain-text (org-timestamp-translate timestamp) info))) + (format + (plist-get info + (cl-case (org-element-property :type timestamp) + ((active active-range) :latex-active-timestamp-format) + ((inactive inactive-range) :latex-inactive-timestamp-format) + (otherwise :latex-diary-timestamp-format))) + value))) + + +;;;; Underline + +(defun org-latex-underline (_underline contents info) + "Transcode UNDERLINE from Org to LaTeX. +CONTENTS is the text with underline markup. INFO is a plist +holding contextual information." + (org-latex--text-markup contents 'underline info)) + + +;;;; Verbatim + +(defun org-latex-verbatim (verbatim _contents info) + "Transcode a VERBATIM object from Org to LaTeX. +CONTENTS is nil. INFO is a plist used as a communication +channel." + (org-latex--text-markup + (org-element-property :value verbatim) 'verbatim info)) + + +;;;; Verse Block + +(defun org-latex-verse-block (verse-block contents info) + "Transcode a VERSE-BLOCK element from Org to LaTeX. +CONTENTS is verse block contents. INFO is a plist holding +contextual information." + (let* ((lin (org-export-read-attribute :attr_latex verse-block :lines)) + (latcode (org-export-read-attribute :attr_latex verse-block :latexcode)) + (cent (org-export-read-attribute :attr_latex verse-block :center)) + (attr (concat + (if cent "[\\versewidth]" "") + (if lin (format "\n\\poemlines{%s}" lin) "") + (if latcode (format "\n%s" latcode) ""))) + (versewidth (org-export-read-attribute :attr_latex verse-block :versewidth)) + (vwidth (if versewidth (format "\\settowidth{\\versewidth}{%s}\n" versewidth) "")) + (linreset (if lin "\n\\poemlines{0}" ""))) + (concat + (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. + (format "%s\\begin{verse}%s\n%s\\end{verse}%s" + vwidth + attr + (replace-regexp-in-string + "^[ \t]+" (lambda (m) (format "\\hspace*{%dem}" (length m))) + (replace-regexp-in-string + "^[ \t]*\\\\\\\\$" "\\vspace*{1em}" + (replace-regexp-in-string + "\\([ \t]*\\\\\\\\\\)?[ \t]*\n" "\\\\\n" + contents nil t) nil t) nil t) linreset) + info) + ;; Insert footnote definitions, if any, after the environment, so + ;; the special formatting above is not applied to them. + (org-latex--delayed-footnotes-definitions verse-block info)))) + + +;;; End-user functions + +;;;###autoload +(defun org-latex-export-as-latex + (&optional async subtreep visible-only body-only ext-plist) + "Export current buffer as a LaTeX buffer. + +If narrowing is active in the current buffer, only export its +narrowed part. + +If a region is active, export that region. + +A non-nil optional argument ASYNC means the process should happen +asynchronously. The resulting buffer should be accessible +through the `org-export-stack' interface. + +When optional argument SUBTREEP is non-nil, export the sub-tree +at point, extracting information from the headline properties +first. + +When optional argument VISIBLE-ONLY is non-nil, don't export +contents of hidden elements. + +When optional argument BODY-ONLY is non-nil, only write code +between \"\\begin{document}\" and \"\\end{document}\". + +EXT-PLIST, when provided, is a property list with external +parameters overriding Org default settings, but still inferior to +file-local settings. + +Export is done in a buffer named \"*Org LATEX Export*\", which +will be displayed when `org-export-show-temporary-export-buffer' +is non-nil." + (interactive) + (org-export-to-buffer 'latex "*Org LATEX Export*" + async subtreep visible-only body-only ext-plist (lambda () (LaTeX-mode)))) + +;;;###autoload +(defun org-latex-convert-region-to-latex () + "Assume the current region has Org syntax, and convert it to LaTeX. +This can be used in any buffer. For example, you can write an +itemized list in Org syntax in an LaTeX buffer and use this +command to convert it." + (interactive) + (org-export-replace-region-by 'latex)) + +;;;###autoload +(defun org-latex-export-to-latex + (&optional async subtreep visible-only body-only ext-plist) + "Export current buffer to a LaTeX file. + +If narrowing is active in the current buffer, only export its +narrowed part. + +If a region is active, export that region. + +A non-nil optional argument ASYNC means the process should happen +asynchronously. The resulting file should be accessible through +the `org-export-stack' interface. + +When optional argument SUBTREEP is non-nil, export the sub-tree +at point, extracting information from the headline properties +first. + +When optional argument VISIBLE-ONLY is non-nil, don't export +contents of hidden elements. + +When optional argument BODY-ONLY is non-nil, only write code +between \"\\begin{document}\" and \"\\end{document}\". + +EXT-PLIST, when provided, is a property list with external +parameters overriding Org default settings, but still inferior to +file-local settings." + (interactive) + (let ((outfile (org-export-output-file-name ".tex" subtreep))) + (org-export-to-file 'latex outfile + async subtreep visible-only body-only ext-plist))) + +;;;###autoload +(defun org-latex-export-to-pdf + (&optional async subtreep visible-only body-only ext-plist) + "Export current buffer to LaTeX then process through to PDF. + +If narrowing is active in the current buffer, only export its +narrowed part. + +If a region is active, export that region. + +A non-nil optional argument ASYNC means the process should happen +asynchronously. The resulting file should be accessible through +the `org-export-stack' interface. + +When optional argument SUBTREEP is non-nil, export the sub-tree +at point, extracting information from the headline properties +first. + +When optional argument VISIBLE-ONLY is non-nil, don't export +contents of hidden elements. + +When optional argument BODY-ONLY is non-nil, only write code +between \"\\begin{document}\" and \"\\end{document}\". + +EXT-PLIST, when provided, is a property list with external +parameters overriding Org default settings, but still inferior to +file-local settings. + +Return PDF file's name." + (interactive) + (let ((outfile (org-export-output-file-name ".tex" subtreep))) + (org-export-to-file 'latex outfile + async subtreep visible-only body-only ext-plist + #'org-latex-compile))) + +(defun org-latex-compile (texfile &optional snippet) + "Compile a TeX file. + +TEXFILE is the name of the file being compiled. Processing is +done through the command specified in `org-latex-pdf-process', +which see. Output is redirected to \"*Org PDF LaTeX Output*\" +buffer. + +When optional argument SNIPPET is non-nil, TEXFILE is a temporary +file used to preview a LaTeX snippet. In this case, do not +create a log buffer and do not remove log files. + +Return PDF file name or raise an error if it couldn't be +produced." + (unless snippet (message "Processing LaTeX file %s..." texfile)) + (let* ((compiler + (or (with-temp-buffer + (save-excursion (insert-file-contents texfile)) + (and (search-forward-regexp (regexp-opt org-latex-compilers) + (line-end-position 2) + t) + (progn (beginning-of-line) (looking-at-p "%")) + (match-string 0))) + "pdflatex")) + (process (if (functionp org-latex-pdf-process) org-latex-pdf-process + ;; Replace "%latex" with "%L" and "%bib" and + ;; "%bibtex" with "%B" to adhere to `format-spec' + ;; specifications. + (mapcar (lambda (command) + (replace-regexp-in-string + "%\\(?:\\(?:bib\\|la\\)tex\\|bib\\)\\>" + (lambda (m) (upcase (substring m 0 2))) + command)) + org-latex-pdf-process))) + (spec `((?B . ,(shell-quote-argument org-latex-bib-compiler)) + (?L . ,(shell-quote-argument compiler)))) + (log-buf-name "*Org PDF LaTeX Output*") + (log-buf (and (not snippet) (get-buffer-create log-buf-name))) + (outfile (org-compile-file texfile process "pdf" + (format "See %S for details" log-buf-name) + log-buf spec))) + (unless snippet + (when org-latex-remove-logfiles + (mapc #'delete-file + (directory-files + (file-name-directory outfile) + t + (concat (regexp-quote (file-name-base outfile)) + "\\(?:\\.[0-9]+\\)?\\." + (regexp-opt org-latex-logfiles-extensions)) + t))) + (let ((warnings (org-latex--collect-warnings log-buf))) + (message (concat "PDF file produced" + (cond + ((eq warnings 'error) " with errors.") + (warnings (concat " with warnings: " warnings)) + (t ".")))))) + ;; Return output file name. + outfile)) + +(defun org-latex--collect-warnings (buffer) + "Collect some warnings from \"pdflatex\" command output. +BUFFER is the buffer containing output. Return collected +warnings types as a string, `error' if a LaTeX error was +encountered or nil if there was none." + (with-current-buffer buffer + (save-excursion + (goto-char (point-max)) + (when (re-search-backward "^[ \t]*This is .*?TeX.*?Version" nil t) + (if (re-search-forward "^!" nil t) 'error + (let ((case-fold-search t) + (warnings "")) + (dolist (warning org-latex-known-warnings) + (when (save-excursion (re-search-forward (car warning) nil t)) + (setq warnings (concat warnings " " (cdr warning))))) + (org-string-nw-p (org-trim warnings)))))))) + +;;;###autoload +(defun org-latex-publish-to-latex (plist filename pub-dir) + "Publish an Org file to LaTeX. + +FILENAME is the filename of the Org file to be published. PLIST +is the property list for the given project. PUB-DIR is the +publishing directory. + +Return output file name." + (org-publish-org-to 'latex filename ".tex" plist pub-dir)) + +;;;###autoload +(defun org-latex-publish-to-pdf (plist filename pub-dir) + "Publish an Org file to PDF (via LaTeX). + +FILENAME is the filename of the Org file to be published. PLIST +is the property list for the given project. PUB-DIR is the +publishing directory. + +Return output file name." + ;; Unlike to `org-latex-publish-to-latex', PDF file is generated + ;; in working directory and then moved to publishing directory. + (org-publish-attachment + plist + ;; Default directory could be anywhere when this function is + ;; called. We ensure it is set to source file directory during + ;; compilation so as to not break links to external documents. + (let ((default-directory (file-name-directory filename))) + (org-latex-compile + (org-publish-org-to + 'latex filename ".tex" plist (file-name-directory filename)))) + pub-dir)) + + +(provide 'ox-latex) + +;; Local variables: +;; generated-autoload-file: "org-loaddefs.el" +;; End: + +;;; ox-latex.el ends here |