summaryrefslogtreecommitdiff
path: root/lisp/ox-latex.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/ox-latex.el')
-rw-r--r--lisp/ox-latex.el1924
1 files changed, 1256 insertions, 668 deletions
diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el
index 2c71f7d..c3eb1ea 100644
--- a/lisp/ox-latex.el
+++ b/lisp/ox-latex.el
@@ -1,6 +1,6 @@
;;; ox-latex.el --- LaTeX Back-End for Org Export Engine
-;; Copyright (C) 2011-2014 Free Software Foundation, Inc.
+;; Copyright (C) 2011-2015 Free Software Foundation, Inc.
;; Author: Nicolas Goaziou <n.goaziou at gmail dot com>
;; Keywords: outlines, hypermedia, calendar, wp
@@ -43,8 +43,6 @@
(center-block . org-latex-center-block)
(clock . org-latex-clock)
(code . org-latex-code)
- (comment . (lambda (&rest args) ""))
- (comment-block . (lambda (&rest args) ""))
(drawer . org-latex-drawer)
(dynamic-block . org-latex-dynamic-block)
(entity . org-latex-entity)
@@ -65,13 +63,13 @@
(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 . (lambda (&rest args) ""))
+ (property-drawer . org-latex-property-drawer)
(quote-block . org-latex-quote-block)
- (quote-section . org-latex-quote-section)
(radio-target . org-latex-radio-target)
(section . org-latex-section)
(special-block . org-latex-special-block)
@@ -88,7 +86,10 @@
(timestamp . org-latex-timestamp)
(underline . org-latex-underline)
(verbatim . org-latex-verbatim)
- (verse-block . org-latex-verse-block))
+ (verse-block . org-latex-verse-block)
+ ;; Pseudo objects and elements.
+ (latex-math-block . org-latex-math-block)
+ (latex-matrices . org-latex-matrices))
:export-block '("LATEX" "TEX")
:menu-entry
'(?l "Export to LaTeX"
@@ -99,13 +100,52 @@
(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)))))))
- :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)
- (:latex-hyperref-p nil "texht" org-latex-with-hyperref t)
- ;; Redefine regular options.
- (:date "DATE" nil "\\today" t)))
+ :filters-alist '((:filter-options . org-latex-math-block-options-filter)
+ (:filter-parse-tree org-latex-math-block-tree-filter
+ org-latex-matrices-tree-filter))
+ :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-table-mode nil nil org-latex-default-table-mode)
+ (:latex-diary-timestamp-format nil nil org-latex-diary-timestamp-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-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-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)
+ ;; Redefine regular options.
+ (:date "DATE" nil "\\today" parse)))
@@ -164,11 +204,112 @@
("uk" . "ukrainian"))
"Alist between language code and corresponding Babel option.")
+(defconst org-latex-polyglossia-language-alist
+ '(("am" "amharic")
+ ("ast" "asturian")
+ ("ar" "arabic")
+ ("bo" "tibetan")
+ ("bn" "bengali")
+ ("bg" "bulgarian")
+ ("br" "breton")
+ ("bt-br" "brazilian")
+ ("ca" "catalan")
+ ("cop" "coptic")
+ ("cs" "czech")
+ ("cy" "welsh")
+ ("da" "danish")
+ ("de" "german" "german")
+ ("de-at" "german" "austrian")
+ ("de-de" "german" "german")
+ ("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")
+ ("hu" "magyar")
+ ("hy" "armenian")
+ ("id" "bahasai")
+ ("ia" "interlingua")
+ ("is" "icelandic")
+ ("it" "italian")
+ ("kn" "kannada")
+ ("la" "latin" "modern")
+ ("la-modern" "latin" "modern")
+ ("la-classic" "latin" "classic")
+ ("la-medieval" "latin" "medieval")
+ ("lo" "lao")
+ ("lt" "lithuanian")
+ ("lv" "latvian")
+ ("mr" "maranthi")
+ ("ml" "malayalam")
+ ("nl" "dutch")
+ ("nb" "norsk")
+ ("nn" "nynorsk")
+ ("nko" "nko")
+ ("no" "norsk")
+ ("oc" "occitan")
+ ("pl" "polish")
+ ("pms" "piedmontese")
+ ("pt" "portuges")
+ ("rm" "romansh")
+ ("ro" "romanian")
+ ("ru" "russian")
+ ("sa" "sanskrit")
+ ("hsb" "usorbian")
+ ("dsb" "lsorbian")
+ ("sk" "slovak")
+ ("sl" "slovenian")
+ ("se" "samin")
+ ("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" . "\\\\"))
+ ("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
@@ -178,6 +319,79 @@
: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 "25.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_LATEX
+ And this is still section \\ref{sec:foo}.
+ #+END_LATEX
+
+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}.
+
+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 "25.1"
+ :package-version '(Org . "8.3"))
;;;; Preamble
@@ -264,11 +478,15 @@ 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}\",
-AUTO will be replaced with the language related to the language
-code specified by `org-export-default-language', which see. Note
-that constructions such as \"\\usepackage[french,AUTO,english]{babel}\"
-are permitted.
+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
------------------------
@@ -328,11 +546,42 @@ are written as utf8 files."
(defcustom org-latex-title-command "\\maketitle"
"The command used to insert the title just after \\begin{document}.
-If this string contains the formatting specification \"%s\" then
-it will be used as a formatting string, passing the title as an
-argument."
+
+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)
+ :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 "25.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 "25.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.
@@ -341,10 +590,32 @@ the toc:nil option, not to those generated with #+TOC keyword."
:group 'org-export-latex
:type 'string)
-(defcustom org-latex-with-hyperref t
- "Toggle insertion of \\hypersetup{...} in the preamble."
+(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: \"%%\".
+
+Setting :latex-hyperref-template in publishing projects will take
+precedence over this variable."
:group 'org-export-latex
- :type 'boolean)
+ :version "25.1"
+ :package-version '(Org . "8.3")
+ :type '(string :tag "Format string"))
;;;; Headline
@@ -352,17 +623,15 @@ the toc:nil option, not to those generated with #+TOC keyword."
'org-latex-format-headline-default-function
"Function for formatting the headline's text.
-This function will be called with 5 arguments:
-TODO the todo keyword (string or nil).
+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 as a list of strings (list of strings 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.
-
-Use `org-latex-format-headline-default-function' by default,
-which format headlines like for Org version prior to 8.0."
+The function result will be used in the section format string."
:group 'org-export-latex
:version "24.4"
:package-version '(Org . "8.0")
@@ -489,12 +758,14 @@ When modifying this variable, it may be useful to change
:type '(choice (const :tag "Table" table)
(const :tag "Matrix" math)
(const :tag "Inline matrix" inline-math)
- (const :tag "Verbatim" verbatim)))
+ (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)
+ :type 'boolean
+ :safe #'booleanp)
(defcustom org-latex-tables-booktabs nil
"When non-nil, display tables in a formal \"booktabs\" style.
@@ -505,13 +776,8 @@ attributes."
:group 'org-export-latex
:version "24.4"
:package-version '(Org . "8.0")
- :type 'boolean)
-
-(defcustom org-latex-table-caption-above t
- "When non-nil, place caption string at the beginning of the table.
-Otherwise, place it near the end."
- :group 'org-export-latex
- :type 'boolean)
+ :type 'boolean
+ :safe #'booleanp)
(defcustom org-latex-table-scientific-notation "%s\\,(%s)"
"Format string to display numbers in scientific notation.
@@ -526,11 +792,10 @@ When nil, no transformation is made."
(string :tag "Format string")
(const :tag "No formatting" nil)))
-
;;;; Text markup
(defcustom org-latex-text-markup-alist '((bold . "\\textbf{%s}")
- (code . verb)
+ (code . protectedtexttt)
(italic . "\\emph{%s}")
(strike-through . "\\sout{%s}")
(underline . "\\uline{%s}")
@@ -550,6 +815,8 @@ 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 "25.1"
+ :package-version '(Org . "8.3")
:type 'alist
:options '(bold code italic strike-through underline verbatim))
@@ -575,44 +842,24 @@ The default function simply returns the value of CONTENTS."
;;;; Inlinetasks
-(defcustom org-latex-format-inlinetask-function 'ignore
+(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 six parameters:
- TODO the todo keyword, as a string
- TODO-TYPE the todo type, a symbol among `todo', `done' and nil.
- PRIORITY the inlinetask priority, as a string
- NAME the inlinetask name, as a string.
- TAGS the inlinetask tags, as a list of strings.
- CONTENTS the contents of the inlinetask, as a string.
-
-The function should return the string to be exported.
+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)
-For example, the variable could be set to the following function
-in order to mimic default behaviour:
-
-\(defun org-latex-format-inlinetask \(todo type priority name tags contents\)
-\"Format an inline task element for LaTeX export.\"
- \(let ((full-title
- \(concat
- \(when todo
- \(format \"\\\\textbf{\\\\textsf{\\\\textsc{%s}}} \" todo))
- \(when priority (format \"\\\\framebox{\\\\#%c} \" priority))
- title
- \(when tags
- \(format \"\\\\hfill{}\\\\textsc{:%s:}\"
- \(mapconcat 'identity tags \":\")))))
- \(format (concat \"\\\\begin{center}\\n\"
- \"\\\\fbox{\\n\"
- \"\\\\begin{minipage}[c]{.6\\\\textwidth}\\n\"
- \"%s\\n\\n\"
- \"\\\\rule[.8em]{\\\\textwidth}{2pt}\\n\\n\"
- \"%s\"
- \"\\\\end{minipage}}\"
- \"\\\\end{center}\")
- full-title contents))"
+The function should return the string to be exported."
:group 'org-export-latex
- :type 'function)
+ :type 'function
+ :version "25.1"
+ :package-version '(Org . "8.3"))
;; Src blocks
@@ -640,7 +887,7 @@ the minted package to `org-latex-packages-alist', for example
using customize, or with
\(require 'ox-latex)
- \(add-to-list 'org-latex-packages-alist '(\"\" \"minted\"))
+ \(add-to-list 'org-latex-packages-alist '(\"newfloat\" \"minted\"))
In addition, it is necessary to install pygments
\(http://pygments.org), and to configure the variable
@@ -656,7 +903,8 @@ into previewing problems, please consult
:type '(choice
(const :tag "Use listings" t)
(const :tag "Use minted" minted)
- (const :tag "Export verbatim" nil)))
+ (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")
@@ -668,7 +916,8 @@ into previewing problems, please consult
(shell-script "bash")
(gnuplot "Gnuplot")
(ocaml "Caml") (caml "Caml")
- (sql "SQL") (sqlite "sql"))
+ (sql "SQL") (sqlite "sql")
+ (makefile "make"))
"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
@@ -676,6 +925,8 @@ 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 "24.4"
+ :package-version '(Org . "8.3")
:type '(repeat
(list
(symbol :tag "Major mode ")
@@ -697,7 +948,13 @@ 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."
+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
@@ -744,7 +1001,13 @@ will result in src blocks being exported with
\\begin{minted}[bgcolor=bg,frame=lines]{<LANG>}
as the start of the minted environment. Note that the same
-options will be applied to blocks of all languages."
+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
@@ -840,11 +1103,14 @@ file name as its single argument."
(function)))
(defcustom org-latex-logfiles-extensions
- '("aux" "idx" "log" "out" "toc" "nav" "snm" "vrb")
+ '("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 remove if `org-latex-remove-logfiles' is
+The logfiles will be removed if `org-latex-remove-logfiles' is
non-nil."
:group 'org-export-latex
+ :version "25.1"
+ :package-version '(Org . "8.3")
:type '(repeat (string :tag "Extension")))
(defcustom org-latex-remove-logfiles t
@@ -855,19 +1121,20 @@ logfiles to remove, set `org-latex-logfiles-extensions'."
:group 'org-export-latex
:type 'boolean)
-(defcustom org-latex-known-errors
- '(("Reference.*?undefined" . "[undefined reference]")
- ("Citation.*?undefined" . "[undefined citation]")
- ("Undefined control sequence" . "[undefined control sequence]")
- ("^! LaTeX.*?Error" . "[LaTeX error]")
- ("^! Package.*?Error" . "[package error]")
- ("Runaway argument" . "Runaway argument"))
+(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 errors in the
-log of a latex-run."
+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 "24.4"
- :package-version '(Org . "8.0")
+ :version "25.1"
+ :package-version '(Org . "8.3")
:type '(repeat
(cons
(string :tag "Regexp")
@@ -877,6 +1144,54 @@ log of a latex-run."
;;; 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
+ (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 (case type
+ (headline "sec:")
+ (table "tab:")
+ (latex-environment
+ (and (org-string-match-p
+ org-latex-math-environments-re
+ (org-element-property :value datum))
+ "eq:"))
+ (paragraph
+ (and (org-element-property :caption datum)
+ "fig:")))
+ (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.
@@ -884,25 +1199,39 @@ 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-element-property :name element))
- (label-str (if (not (org-string-nw-p label)) ""
- (format "\\label{%s}"
- (org-export-solidify-link-text 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))
+ (memq (plist-get info :latex-listings)
+ '(nil minted)))))
(short (org-export-get-caption element t))
- (caption-from-attr-latex (org-export-read-attribute :attr_latex element :caption)))
+ (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-str "")) "")
- ((not main) (concat label-str "\n"))
+ ((and (not main) (equal label "")) "")
+ ((not main) (concat label "\n"))
;; Option caption format with short name.
- (short (format "\\caption[%s]{%s%s}\n"
- (org-export-data short info)
- label-str
- (org-export-data main info)))
- ;; Standard caption format.
- (t (format "\\caption{%s%s}\n" label-str (org-export-data main info))))))
+ (t
+ (format (if nonfloat "\\captionof{%s}%s{%s%s}\n"
+ "\\caption%s%s{%s%s}\n")
+ (if nonfloat
+ (case type
+ (paragraph "figure")
+ (src-block (if (plist-get info :latex-listings)
+ "listing"
+ "figure"))
+ (t (symbol-name type)))
+ "")
+ (if short (format "[%s]" (org-export-data short info)) "")
+ label
+ (org-export-data main info))))))
(defun org-latex-guess-inputenc (header)
"Set the coding system in inputenc to what the buffer is.
@@ -958,6 +1287,59 @@ Return the new header."
", ")
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--find-verb-separator (s)
"Return a character not used in string S.
This is used to choose a separator for constructs like \\verb."
@@ -978,52 +1360,50 @@ nil."
options
","))
-(defun org-latex--wrap-label (element output)
+(defun org-latex--wrap-label (element output info)
"Wrap label associated to ELEMENT around OUTPUT, if appropriate.
-This function shouldn't be used for floats. See
+INFO is the current export state, as a plist. This function
+should not be used for floats. See
`org-latex--caption/label-string'."
- (let ((label (org-element-property :name element)))
- (if (not (and (org-string-nw-p output) (org-string-nw-p label))) output
- (concat (format "\\label{%s}\n" (org-export-solidify-link-text label))
- output))))
-
-(defun org-latex--text-markup (text markup)
+ (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
+ "--\\|[\\{}$%&_#~^]"
+ (lambda (m)
+ (cond ((equal m "--") "-{}-")
+ ((equal m "\\") "\\textbackslash{}")
+ ((equal m "~") "\\textasciitilde{}")
+ ((equal m "^") "\\textasciicircum{}")
+ (t (concat "\\" m))))
+ text nil t))
+
+(defun org-latex--text-markup (text markup info)
"Format TEXT depending on MARKUP text markup.
-See `org-latex-text-markup-alist' for details."
- (let ((fmt (cdr (assq markup org-latex-text-markup-alist))))
- (cond
- ;; No format string: Return raw text.
- ((not fmt) text)
- ;; Handle the `verb' special case: Find and appropriate separator
- ;; and use "\\verb" command.
- ((eq 'verb fmt)
- (let ((separator (org-latex--find-verb-separator text)))
- (concat "\\verb" separator
- (replace-regexp-in-string "\n" " " text)
- separator)))
- ;; Handle the `protectedtexttt' special case: Protect some
- ;; special chars and use "\texttt{%s}" format string.
- ((eq 'protectedtexttt fmt)
- (let ((start 0)
- (trans '(("\\" . "\\textbackslash{}")
- ("~" . "\\textasciitilde{}")
- ("^" . "\\textasciicircum{}")))
- (rtn "")
- char)
- (while (string-match "[\\{}$%&_#~^]" text)
- (setq char (match-string 0 text))
- (if (> (match-beginning 0) 0)
- (setq rtn (concat rtn (substring text 0 (match-beginning 0)))))
- (setq text (substring text (1+ (match-beginning 0))))
- (setq char (or (cdr (assoc char trans)) (concat "\\" char))
- rtn (concat rtn char)))
- (setq text (concat rtn text)
- fmt "\\texttt{%s}")
- (while (string-match "--" text)
- (setq text (replace-match "-{}-" t t text)))
- (format fmt text)))
- ;; Else use format string.
- (t (format fmt text)))))
+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)))))
+ (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)))
+ ;; Handle the `protectedtexttt' special case: Protect some
+ ;; special chars and use "\texttt{%s}" format string.
+ (protectedtexttt
+ (format "\\texttt{%s}" (org-latex--protect-text text)))
+ ;; Else use format string.
+ (t (format fmt text)))))
(defun org-latex--delayed-footnotes-definitions (element info)
"Return footnotes definitions in ELEMENT as a string.
@@ -1065,6 +1445,57 @@ just outside of it."
(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 lang org-latex-babel-language-alist))
+ lang))))
+ `((?a . ,(org-export-data (plist-get info :author) info))
+ (?t . ,(org-export-data (plist-get info :title) 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--make-header (info)
+ "Return a formatted LaTeX header.
+INFO is a plist used as a communication channel."
+ (let* ((class (plist-get info :latex-class))
+ (class-options (plist-get info :latex-class-options))
+ (header (nth 1 (assoc class (plist-get info :latex-classes))))
+ (document-class-string
+ (and (stringp header)
+ (if (not class-options) header
+ (replace-regexp-in-string
+ "^[ \t]*\\\\documentclass\\(\\(\\[[^]]*\\]\\)?\\)"
+ class-options header t nil 1)))))
+ (if (not document-class-string)
+ (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
+ document-class-string
+ org-latex-default-packages-alist
+ org-latex-packages-alist nil
+ (concat (org-element-normalize-string
+ (plist-get info :latex-header))
+ (plist-get info :latex-header-extra)))))
+ info)
+ info))))
;;; Template
@@ -1073,34 +1504,14 @@ just outside of it."
"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)))
+ (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"))
;; Document class and packages.
- (let* ((class (plist-get info :latex-class))
- (class-options (plist-get info :latex-class-options))
- (header (nth 1 (assoc class org-latex-classes)))
- (document-class-string
- (and (stringp header)
- (if (not class-options) header
- (replace-regexp-in-string
- "^[ \t]*\\\\documentclass\\(\\(\\[[^]]*\\]\\)?\\)"
- class-options header t nil 1)))))
- (if (not document-class-string)
- (user-error "Unknown LaTeX class `%s'" class)
- (org-latex-guess-babel-language
- (org-latex-guess-inputenc
- (org-element-normalize-string
- (org-splice-latex-header
- document-class-string
- org-latex-default-packages-alist
- org-latex-packages-alist nil
- (concat (org-element-normalize-string
- (plist-get info :latex-header))
- (plist-get info :latex-header-extra)))))
- info)))
+ (org-latex--make-header info)
;; Possibly limit depth for headline numbering.
(let ((sec-num (plist-get info :section-numbers)))
(when (integerp sec-num)
@@ -1117,40 +1528,46 @@ holding export options."
;; Date.
(let ((date (and (plist-get info :with-date) (org-export-get-date info))))
(format "\\date{%s}\n" (org-export-data date info)))
- ;; Title
- (format "\\title{%s}\n" title)
+ ;; 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.
- (when (plist-get info :latex-hyperref-p)
- (format "\\hypersetup{\n pdfkeywords={%s},\n pdfsubject={%s},\n pdfcreator={%s}}\n"
- (or (plist-get info :keywords) "")
- (or (plist-get info :description) "")
- (if (not (plist-get info :with-creator)) ""
- (plist-get info :creator))))
+ (let ((template (plist-get info :latex-hyperref-template)))
+ (and (stringp template)
+ (format-spec template spec)))
;; Document start.
"\\begin{document}\n\n"
;; Title command.
- (org-element-normalize-string
- (cond ((string= "" title) nil)
- ((not (stringp org-latex-title-command)) nil)
- ((string-match "\\(?:[^%]\\|^\\)%s"
- org-latex-title-command)
- (format org-latex-title-command title))
- (t org-latex-title-command)))
+ (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 (wholenump depth)
(format "\\setcounter{tocdepth}{%d}\n" depth))
- org-latex-toc-command)))
+ (plist-get info :latex-toc-command))))
;; Document's body.
contents
;; Creator.
- (let ((creator-info (plist-get info :with-creator)))
- (cond
- ((not creator-info) "")
- ((eq creator-info 'comment)
- (format "%% %s\n" (plist-get info :creator)))
- (t (concat (plist-get info :creator) "\n"))))
+ (and (plist-get info :with-creator)
+ (concat (plist-get info :creator) "\n"))
;; Document end.
"\\end{document}")))
@@ -1164,7 +1581,7 @@ holding export options."
"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))
+ (org-latex--text-markup contents 'bold info))
;;;; Center Block
@@ -1174,8 +1591,7 @@ contextual information."
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)))
+ center-block (format "\\begin{center}\n%s\\end{center}" contents) info))
;;;; Clock
@@ -1187,10 +1603,8 @@ information."
(concat
"\\noindent"
(format "\\textbf{%s} " org-clock-string)
- (format org-latex-inactive-timestamp-format
- (concat (org-translate-time
- (org-element-property :raw-value
- (org-element-property :value clock)))
+ (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)))))
"\\\\"))
@@ -1202,7 +1616,7 @@ information."
"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))
+ (org-latex--text-markup (org-element-property :value code) 'code info))
;;;; Drawer
@@ -1212,9 +1626,9 @@ channel."
CONTENTS holds the contents of the block. INFO is a plist
holding contextual information."
(let* ((name (org-element-property :drawer-name drawer))
- (output (funcall org-latex-format-drawer-function
+ (output (funcall (plist-get info :latex-format-drawer-function)
name contents)))
- (org-latex--wrap-label drawer output)))
+ (org-latex--wrap-label drawer output info)))
;;;; Dynamic Block
@@ -1223,7 +1637,7 @@ holding contextual information."
"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))
+ (org-latex--wrap-label dynamic-block contents info))
;;;; Entity
@@ -1232,8 +1646,7 @@ holding contextual information. See `org-export-data'."
"Transcode an ENTITY object from Org to LaTeX.
CONTENTS are the definition itself. INFO is a plist holding
contextual information."
- (let ((ent (org-element-property :latex entity)))
- (if (org-element-property :latex-math-p entity) (format "$%s$" ent) ent)))
+ (org-element-property :latex entity))
;;;; Example Block
@@ -1243,10 +1656,16 @@ contextual information."
CONTENTS is nil. INFO is a plist holding contextual
information."
(when (org-string-nw-p (org-element-property :value example-block))
- (org-latex--wrap-label
- example-block
- (format "\\begin{verbatim}\n%s\\end{verbatim}"
- (org-export-format-code-default example-block info)))))
+ (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
@@ -1276,7 +1695,8 @@ CONTENTS is nil. INFO is a plist holding contextual information."
fixed-width
(format "\\begin{verbatim}\n%s\\end{verbatim}"
(org-remove-indentation
- (org-element-property :value fixed-width)))))
+ (org-element-property :value fixed-width)))
+ info))
;;;; Footnote Reference
@@ -1288,7 +1708,7 @@ CONTENTS is nil. INFO is a plist holding contextual information."
;; 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)
- org-latex-footnote-separator))
+ (plist-get info :latex-footnote-separator)))
(cond
;; Use \footnotemark if the footnote has already been defined.
((not (org-export-footnote-first-reference-p footnote-reference info))
@@ -1296,9 +1716,8 @@ CONTENTS is nil. INFO is a plist holding contextual information."
(org-export-get-footnote-number footnote-reference info)))
;; Use \footnotemark if reference is within another footnote
;; reference, footnote definition or table cell.
- ((loop for parent in (org-export-get-genealogy footnote-reference)
- thereis (memq (org-element-type parent)
- '(footnote-reference footnote-definition table-cell)))
+ ((org-element-lineage footnote-reference
+ '(footnote-reference footnote-definition table-cell))
"\\footnotemark")
;; Otherwise, define it with \footnote command.
(t
@@ -1321,7 +1740,7 @@ holding contextual information."
(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 org-latex-classes))
+ (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
@@ -1365,16 +1784,12 @@ holding contextual information."
(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 org-latex-format-headline-function
- todo todo-type priority text tags))
+ (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
- (format "\\label{sec-%s}\n"
- (mapconcat 'number-to-string
- (org-export-get-headline-number headline info)
- "-")))
+ (headline-label (org-latex--label headline info t t))
(pre-blanks
- (make-string (org-element-property :pre-blank headline) 10)))
+ (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
@@ -1404,15 +1819,32 @@ holding contextual information."
;; an alternative heading when possible, and when this is not
;; identical to the usual heading.
(let ((opt-title
- (funcall org-latex-format-headline-function
+ (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))))
- (if (and numberedp opt-title
+ (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 (org-string-match-p "\\<headlines\\>" v)
+ (org-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))
+ (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
@@ -1427,7 +1859,7 @@ holding contextual information."
(concat headline-label pre-blanks contents))))))))
(defun org-latex-format-headline-default-function
- (todo todo-type priority text tags)
+ (todo todo-type priority text tags info)
"Default format function for a headline.
See `org-latex-format-headline-function' for details."
(concat
@@ -1435,7 +1867,9 @@ See `org-latex-format-headline-function' for details."
(and priority (format "\\framebox{\\#%c} " priority))
text
(and tags
- (format "\\hfill{}\\textsc{%s}" (mapconcat 'identity tags ":")))))
+ (format "\\hfill{}\\textsc{%s}"
+ (mapconcat (lambda (tag) (org-latex-plain-text tag info))
+ tags ":")))))
;;;; Horizontal Rule
@@ -1456,7 +1890,8 @@ CONTENTS is nil. INFO is a plist holding contextual information."
horizontal-rule
(format "\\rule{%s}{%s}"
(or (plist-get attr :width) "\\linewidth")
- (or (plist-get attr :thickness) "0.5pt"))))))
+ (or (plist-get attr :thickness) "0.5pt"))
+ info))))
;;;; Inline Src Block
@@ -1467,34 +1902,33 @@ 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)))
- (cond
- ;; Do not use a special package: transcode it verbatim.
- ((not org-latex-listings)
- (concat "\\verb" separator code separator))
- ;; Use minted package.
- ((eq org-latex-listings 'minted)
- (let* ((org-lang (org-element-property :language inline-src-block))
- (mint-lang (or (cadr (assq (intern org-lang)
- org-latex-minted-langs))
- (downcase org-lang)))
- (options (org-latex--make-option-string
- org-latex-minted-options)))
- (concat (format "\\mint%s{%s}"
- (if (string= options "") "" (format "[%s]" options))
- mint-lang)
- separator code separator)))
- ;; Use listings package.
- (t
- ;; Maybe translate language's name.
- (let* ((org-lang (org-element-property :language inline-src-block))
- (lst-lang (or (cadr (assq (intern org-lang)
- org-latex-listings-langs))
- org-lang))
- (options (org-latex--make-option-string
- (append org-latex-listings-options
- `(("language" ,lst-lang))))))
- (concat (format "\\lstinline[%s]" options)
- separator code separator))))))
+ (case (plist-get info :latex-listings)
+ ;; Do not use a special package: transcode it verbatim.
+ ((nil) (format "\\texttt{%s}" (org-latex--protect-text code)))
+ ;; 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))))
+ (concat (format "\\mint%s{%s}"
+ (if (string= options "") "" (format "[%s]" options))
+ mint-lang)
+ separator code separator)))
+ ;; 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
@@ -1511,31 +1945,33 @@ holding contextual information."
(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))))
- ;; If `org-latex-format-inlinetask-function' is provided, call it
- ;; with appropriate arguments.
- (if (not (eq org-latex-format-inlinetask-function 'ignore))
- (funcall org-latex-format-inlinetask-function
- todo todo-type priority title tags contents)
- ;; Otherwise, use a default template.
- (org-latex--wrap-label
- inlinetask
- (let ((full-title
- (concat
- (when todo (format "\\textbf{\\textsf{\\textsc{%s}}} " todo))
- (when priority (format "\\framebox{\\#%c} " priority))
- title
- (when tags (format "\\hfill{}\\textsc{:%s:}"
- (mapconcat #'identity 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}"))))))
+ (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 a 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:}"
+ (mapconcat
+ (lambda (tag) (org-latex-plain-text tag info))
+ 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
@@ -1544,7 +1980,7 @@ holding contextual information."
"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))
+ (org-latex--text-markup contents 'italic info))
;;;; Item
@@ -1621,24 +2057,31 @@ CONTENTS is nil. INFO is a plist holding contextual information."
((string= key "LATEX") value)
((string= key "INDEX") (format "\\index{%s}" value))
((string= key "TOC")
- (let ((value (downcase value)))
+ (let ((case-fold-search t))
(cond
- ((string-match "\\<headlines\\>" value)
- (let ((depth (or (and (string-match "[0-9]+" value)
- (string-to-number (match-string 0 value)))
- (plist-get info :with-toc))))
- (concat
- (when (wholenump depth)
- (format "\\setcounter{tocdepth}{%s}\n" depth))
- "\\tableofcontents")))
- ((string= "tables" value) "\\listoftables")
- ((string= "listings" value)
- (cond
- ((eq org-latex-listings 'minted) "\\listoflistings")
- (org-latex-listings "\\lstlistoflistings")
- ;; At the moment, src blocks with a caption are wrapped
- ;; into a figure environment.
- (t "\\listoffigures")))))))))
+ ((org-string-match-p "\\<headlines\\>" value)
+ (let* ((localp (org-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"))))
+ ((org-string-match-p "\\<tables\\>" value) "\\listoftables")
+ ((org-string-match-p "\\<listings\\>" value)
+ (case (plist-get info :latex-listings)
+ ((nil) "\\listoffigures")
+ (minted "\\listoflistings")
+ (otherwise "\\lstlistoflistings")))))))))
;;;; Latex Environment
@@ -1647,10 +2090,9 @@ CONTENTS is nil. INFO is a plist holding contextual information."
"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 ((label (org-element-property :name latex-environment))
- (value (org-remove-indentation
+ (let ((value (org-remove-indentation
(org-element-property :value latex-environment))))
- (if (not (org-string-nw-p label)) value
+ (if (not (org-element-property :name latex-environment)) value
;; Environment is labeled: label must be within the environment
;; (otherwise, a reference pointing to that element will count
;; the section instead).
@@ -1658,8 +2100,7 @@ CONTENTS is nil. INFO is a plist holding contextual information."
(insert value)
(goto-char (point-min))
(forward-line)
- (insert
- (format "\\label{%s}\n" (org-export-solidify-link-text label)))
+ (insert (org-latex--label latex-environment info nil t))
(buffer-string))))))
@@ -1668,8 +2109,14 @@ CONTENTS is nil. INFO is a plist holding contextual information."
(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."
- (when (plist-get info :with-latex)
- (org-element-property :value latex-fragment)))
+ (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 "\\`\\(\\$\\{1,2\\}\\)\\([^\000]*\\)\\1\\'" value)
+ (match-string 2 value))
+ ((string-match "\\`\\\\(\\([^\000]*\\)\\\\)\\'" value)
+ (match-string 1 value))
+ (t value))))
;;;; Line Break
@@ -1692,36 +2139,41 @@ used as a communication channel."
(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 ((and (not float) (plist-member attr :float)) nil)
- ((string= float "wrap") 'wrap)
+ (cond ((string= float "wrap") 'wrap)
+ ((string= float "sideways") 'sideways)
((string= float "multicolumn") 'multicolumn)
((or float
(org-element-property :caption parent)
(org-string-nw-p (plist-get attr :caption)))
- 'figure))))
+ (if (and (plist-member attr :float) (not float))
+ 'nonfloat
+ 'figure))
+ ((and (not float) (plist-member attr :float)) nil))))
(placement
(let ((place (plist-get attr :placement)))
- (cond (place (format "%s" place))
- ((eq float 'wrap) "{l}{0.5\\textwidth}")
- ((eq float 'figure)
- (format "[%s]" org-latex-default-figure-position))
- (t ""))))
+ (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 ""))))
(comment-include (if (plist-get attr :comment-include) "%" ""))
;; It is possible to specify width and height in the
;; ATTR_LATEX line, and also via default variables.
(width (cond ((plist-get attr :width))
((plist-get attr :height) "")
((eq float 'wrap) "0.48\\textwidth")
- (t org-latex-image-default-width)))
+ (t (plist-get info :latex-image-default-width))))
(height (cond ((plist-get attr :height))
((or (plist-get attr :width)
(memq float '(figure wrap))) "")
- (t org-latex-image-default-height)))
+ (t (plist-get info :latex-image-default-height))))
(options (let ((opt (or (plist-get attr :options)
- org-latex-image-default-option)))
+ (plist-get info :latex-image-default-option))))
(if (not (string-match "\\`\\[\\(.*\\)\\]\\'" opt)) opt
(match-string 1 opt))))
image-code)
@@ -1750,6 +2202,12 @@ used as a communication channel."
(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")
+ (org-string-match-p "\\`[0-9]+\\'" search-option)
+ (not (org-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)) "")
@@ -1769,17 +2227,43 @@ used as a communication channel."
;; Return proper string, depending on FLOAT.
(case float
(wrap (format "\\begin{wrapfigure}%s
-\\centering
+%s\\centering
+%s%s
+%s\\end{wrapfigure}"
+ placement
+ (if caption-above-p caption "")
+ comment-include image-code
+ (if caption-above-p "" caption)))
+ (sideways (format "\\begin{sidewaysfigure}
+%s\\centering
%s%s
-%s\\end{wrapfigure}" placement comment-include image-code caption))
+%s\\end{sidewaysfigure}"
+ (if caption-above-p caption "")
+ comment-include image-code
+ (if caption-above-p "" caption)))
(multicolumn (format "\\begin{figure*}%s
-\\centering
+%s\\centering
%s%s
-%s\\end{figure*}" placement comment-include image-code caption))
+%s\\end{figure*}"
+ placement
+ (if caption-above-p caption "")
+ comment-include image-code
+ (if caption-above-p "" caption)))
(figure (format "\\begin{figure}%s
-\\centering
+%s\\centering
+%s%s
+%s\\end{figure}"
+ placement
+ (if caption-above-p caption "")
+ comment-include image-code
+ (if caption-above-p "" caption)))
+ (nonfloat
+ (format "\\begin{center}
%s%s
-%s\\end{figure}" placement comment-include image-code caption))
+%s\\end{center}"
+ (if caption-above-p caption "")
+ image-code
+ (if caption-above-p "" caption)))
(otherwise image-code))))
(defun org-latex-link (link desc info)
@@ -1794,15 +2278,15 @@ INFO is a plist holding contextual information. See
;; Ensure DESC really exists, or set it to nil.
(desc (and (not (string= desc "")) desc))
(imagep (org-export-inline-image-p
- link org-latex-inline-image-rules))
+ link (plist-get info :latex-inline-image-rules)))
(path (cond
- ((member type '("http" "https" "ftp" "mailto"))
+ ((member type '("http" "https" "ftp" "mailto" "doi"))
(concat type ":" raw-path))
- ((and (string= type "file") (file-name-absolute-p raw-path))
- (concat "file:" raw-path))
- (t raw-path)))
- protocol)
+ ((string= type "file") (org-export-file-uri raw-path))
+ (t raw-path))))
(cond
+ ;; Link type is handled by a special function.
+ ((org-export-custom-protocol-maybe link desc 'latex))
;; Image file.
(imagep (org-latex--inline-image link info))
;; Radio link: Transcode target's contents and use them as link's
@@ -1811,8 +2295,7 @@ INFO is a plist holding contextual information. See
(let ((destination (org-export-resolve-radio-link link info)))
(if (not destination) desc
(format "\\hyperref[%s]{%s}"
- (org-export-solidify-link-text
- (org-element-property :value destination))
+ (org-export-get-reference destination info)
desc))))
;; Links pointing to a headline: Find destination and build
;; appropriate referencing command.
@@ -1826,8 +2309,8 @@ INFO is a plist holding contextual information. See
(if desc (format "\\href{%s}{%s}" destination desc)
(format "\\url{%s}" destination)))
;; Fuzzy link points nowhere.
- ('nil
- (format org-latex-link-with-unknown-path-format
+ ((nil)
+ (format (plist-get info :latex-link-with-unknown-path-format)
(or desc
(org-export-data
(org-element-property :raw-link link) info))))
@@ -1836,12 +2319,7 @@ INFO is a plist holding contextual information. See
;; number. Otherwise, display description or headline's
;; title.
(headline
- (let ((label
- (format "sec-%s"
- (mapconcat
- 'number-to-string
- (org-export-get-headline-number destination info)
- "-"))))
+ (let ((label (org-latex--label destination info t)))
(if (and (not desc)
(org-export-numbered-headline-p destination info))
(format "\\ref{%s}" label)
@@ -1851,23 +2329,32 @@ INFO is a plist holding contextual information. See
(org-element-property :title destination) info))))))
;; Fuzzy link points to a target. Do as above.
(otherwise
- (let ((path (org-export-solidify-link-text path)))
- (if (not desc) (format "\\ref{%s}" path)
- (format "\\hyperref[%s]{%s}" path desc)))))))
+ (let ((ref (org-latex--label destination info t)))
+ (if (not desc) (format "\\ref{%s}" 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)
(org-export-resolve-coderef path info)))
- ;; Link type is handled by a special function.
- ((functionp (setq protocol (nth 2 (assoc type org-link-protocols))))
- (funcall protocol (org-link-unescape path) desc 'latex))
;; External link with a description part.
((and path desc) (format "\\href{%s}{%s}" path desc))
;; External link without a description part.
(path (format "\\url{%s}" path))
;; No path, only description. Try to do something useful.
- (t (format org-latex-link-with-unknown-path-format desc)))))
+ (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
@@ -1898,7 +2385,8 @@ contextual information."
latex-type
(or (plist-get attr :options) "")
contents
- latex-type))))
+ latex-type)
+ info)))
;;;; Plain Text
@@ -1907,47 +2395,35 @@ contextual information."
"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 text))
- ;; Protect %, #, &, $, _, { and }.
- (while (string-match "\\([^\\]\\|^\\)\\([%$#&{}_]\\)" output)
- (setq output
- (replace-match
- (format "\\%s" (match-string 2 output)) nil t output 2)))
- ;; Protect ^.
- (setq output
- (replace-regexp-in-string
- "\\([^\\]\\|^\\)\\(\\^\\)" "\\\\^{}" output nil nil 2))
- ;; Protect \. If special strings are used, be careful not to
- ;; protect "\" in "\-" constructs.
- (let ((symbols (if specialp "-%$#&{}^_\\" "%$#&{}^_\\")))
- (setq output
+ (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
- (format "\\(?:[^\\]\\|^\\)\\(\\\\\\)\\(?:[^%s]\\|$\\)" symbols)
- "$\\backslash$" output nil t 1)))
- ;; Protect ~.
- (setq output
- (replace-regexp-in-string
- "\\([^\\]\\|^\\)\\(~\\)" "\\textasciitilde{}" output nil t 2))
+ "\\<\\(?: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)
+ (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)))
- ;; LaTeX into \LaTeX{} and TeX into \TeX{}.
- (let ((case-fold-search nil)
- (start 0))
- (while (string-match "\\<\\(\\(?:La\\)?TeX\\)\\>" output start)
- (setq output (replace-match
- (format "\\%s{}" (match-string 1 output)) nil t output)
- start (match-end 0))))
;; Convert special strings.
(when specialp
- (setq output
- (replace-regexp-in-string "\\.\\.\\." "\\ldots{}" output nil t)))
+ (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]*\n" " \\\\\\\\\n" output)))
+ "\\(?:[ \t]*\\\\\\\\\\)?[ \t]*\n" "\\\\\n" output nil t)))
;; Return value.
output))
@@ -1968,27 +2444,169 @@ information."
(when closed
(concat
(format "\\textbf{%s} " org-closed-string)
- (format org-latex-inactive-timestamp-format
- (org-translate-time
- (org-element-property :raw-value closed))))))
+ (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 org-latex-active-timestamp-format
- (org-translate-time
- (org-element-property :raw-value deadline))))))
+ (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 org-latex-active-timestamp-format
- (org-translate-time
- (org-element-property :raw-value scheduled))))))))
+ (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)))
+ (matrices
+ (list 'latex-matrices
+ (list :caption caption
+ :markup
+ (cond ((string= mode "inline-math") 'inline)
+ (caption '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-extract-element previous)
+ (org-element-adopt-elements matrices previous)
+ (setq previous next))
+ (org-element-put-property
+ matrices :post-blank (org-element-property :post-blank previous))
+ (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."
+ (format (case (org-element-property :markup matrices)
+ (inline "\\(%s\\)")
+ (equation "\\begin{equation}\n%s\\end{equation}")
+ (t "\\[\n%s\\]"))
+ contents))
+
+(defun org-latex-matrices-tree-filter (tree backend info)
+ (org-latex--wrap-latex-matrices tree info))
+
+;;;; 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
+ (function
+ ;; Non-nil when OBJ can be added to the latex math block.
+ (lambda (obj)
+ (case (org-element-type obj)
+ (entity (org-element-property :latex-math-p obj))
+ (latex-fragment
+ (let ((value (org-element-property :value obj)))
+ (or (org-string-match-p "\\`\\\\([^\000]*\\\\)\\'" value)
+ (org-string-match-p "\\`\\$[^\000]*\\$\\'" value))))
+ ((subscript superscript) t))))))
+ (org-element-map data '(entity latex-fragment subscript superscript)
+ (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)
+ (if (not (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\).
+ (unless (memq (org-element-type next)
+ '(subscript superscript))
+ (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 '(subscript superscript latex-math-block) t)
+ ;; Return updated DATA.
+ data))
+
+(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-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)
@@ -1996,18 +2614,7 @@ information."
CONTENTS holds the contents of the block. INFO is a plist
holding contextual information."
(org-latex--wrap-label
- quote-block
- (format "\\begin{quote}\n%s\\end{quote}" contents)))
-
-
-;;;; Quote Section
-
-(defun org-latex-quote-section (quote-section contents info)
- "Transcode a QUOTE-SECTION element from Org to LaTeX.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (let ((value (org-remove-indentation
- (org-element-property :value quote-section))))
- (when value (format "\\begin{verbatim}\n%s\\end{verbatim}" value))))
+ quote-block (format "\\begin{quote}\n%s\\end{quote}" contents) info))
;;;; Radio Target
@@ -2016,10 +2623,7 @@ CONTENTS is nil. INFO is a plist holding contextual information."
"Transcode a RADIO-TARGET object from Org to LaTeX.
TEXT is the text of the target. INFO is a plist holding
contextual information."
- (format "\\label{%s}%s"
- (org-export-solidify-link-text
- (org-element-property :value radio-target))
- text))
+ (format "\\label{%s}%s" (org-export-get-reference radio-target info) text))
;;;; Section
@@ -2037,14 +2641,14 @@ holding contextual information."
"Transcode a SPECIAL-BLOCK element from Org to LaTeX.
CONTENTS holds the contents of the block. INFO is a plist
holding contextual information."
- (let ((type (downcase (org-element-property :type special-block)))
- (opt (org-export-read-attribute :attr_latex special-block :options)))
+ (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 ""))
- ;; Insert any label or caption within the block
- ;; (otherwise, a reference pointing to that element will
- ;; count the section instead).
- (org-latex--caption/label-string special-block info)
+ (and caption-above-p caption)
contents
+ (and (not caption-above-p) caption)
(format "\\end{%s}" type))))
@@ -2057,6 +2661,7 @@ 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)
@@ -2066,56 +2671,68 @@ contextual information."
(new 0)))
(retain-labels (org-element-property :retain-labels src-block))
(attributes (org-export-read-attribute :attr_latex src-block))
- (float (plist-get attributes :float)))
+ (float (plist-get attributes :float))
+ (listings (plist-get info :latex-listings)))
(cond
;; Case 1. No source fontification.
- ((not org-latex-listings)
+ ((not listings)
(let* ((caption-str (org-latex--caption/label-string src-block info))
(float-env
- (cond ((and (not float) (plist-member attributes :float)) "%s")
- ((string= "multicolumn" float)
- (format "\\begin{figure*}[%s]\n%%s%s\n\\end{figure*}"
- org-latex-default-figure-position
- caption-str))
- ((or caption float)
- (format "\\begin{figure}[H]\n%%s%s\n\\end{figure}"
- caption-str))
+ (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 "")
+ (if caption-above-p "" caption-str)))
+ (caption (concat
+ (if caption-above-p caption-str "")
+ "%s"
+ (if caption-above-p "" (concat "\n" caption-str))))
(t "%s"))))
(format
float-env
(concat (format "\\begin{verbatim}\n%s\\end{verbatim}"
(org-export-format-code-default src-block info))))))
;; Case 2. Custom environment.
- (custom-env (format "\\begin{%s}\n%s\\end{%s}\n"
- custom-env
- (org-export-format-code-default src-block info)
- custom-env))
+ (custom-env
+ (let ((caption-str (org-latex--caption/label-string src-block info)))
+ (format "\\begin{%s}\n%s\\end{%s}\n"
+ custom-env
+ (concat (and caption-above-p caption-str)
+ (org-export-format-code-default src-block info)
+ (and (not caption-above-p) caption-str))
+ custom-env)))
;; Case 3. Use minted package.
- ((eq org-latex-listings 'minted)
+ ((eq listings 'minted)
(let* ((caption-str (org-latex--caption/label-string src-block info))
(float-env
- (cond ((and (not float) (plist-member attributes :float)) "%s")
- ((string= "multicolumn" float)
- (format "\\begin{listing*}\n%%s\n%s\\end{listing*}"
- caption-str))
- ((or caption float)
- (format "\\begin{listing}[H]\n%%s\n%s\\end{listing}"
- caption-str))
- (t "%s")))
+ (cond
+ ((string= "multicolumn" float)
+ (format "\\begin{listing*}\n%s%%s\n%s\\end{listing*}"
+ (if caption-above-p caption-str "")
+ (if caption-above-p "" caption-str)))
+ (caption
+ (concat (if caption-above-p caption-str "")
+ "%s"
+ (if caption-above-p "" (concat "\n" caption-str))))
+ (t "%s")))
+ (options (plist-get info :latex-minted-options))
(body
(format
"\\begin{minted}[%s]{%s}\n%s\\end{minted}"
;; Options.
- (org-latex--make-option-string
- (if (or (not num-start)
- (assoc "linenos" org-latex-minted-options))
- org-latex-minted-options
- (append
- `(("linenos")
- ("firstnumber" ,(number-to-string (1+ num-start))))
- org-latex-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) org-latex-minted-langs))
+ (or (cadr (assq (intern lang)
+ (plist-get info :latex-minted-langs)))
(downcase lang))
;; Source code.
(let* ((code-info (org-export-unravel-code src-block))
@@ -2142,7 +2759,9 @@ contextual information."
;; Case 4. Use listings package.
(t
(let ((lst-lang
- (or (cadr (assq (intern lang) org-latex-listings-langs)) 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))
@@ -2151,28 +2770,32 @@ contextual information."
(format "{%s}" (org-export-data main info))
(format "{[%s]%s}"
(org-export-data secondary info)
- (org-export-data main info)))))))
+ (org-export-data main info))))))
+ (lst-opt (plist-get info :latex-listings-options)))
(concat
;; Options.
(format
"\\lstset{%s}\n"
- (org-latex--make-option-string
- (append
- org-latex-listings-options
- (cond
- ((and (not float) (plist-member attributes :float)) nil)
- ((string= "multicolumn" float) '(("float" "*")))
- ((and float (not (assoc "float" org-latex-listings-options)))
- `(("float" ,org-latex-default-figure-position))))
- `(("language" ,lst-lang))
- (if label `(("label" ,label)) '(("label" " ")))
- (if caption-str `(("caption" ,caption-str)) '(("caption" " ")))
- (cond ((assoc "numbers" org-latex-listings-options) nil)
- ((not num-start) '(("numbers" "none")))
- ((zerop num-start) '(("numbers" "left")))
- (t `(("numbers" "left")
- ("firstnumber"
- ,(number-to-string (1+ num-start)))))))))
+ (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" ,label)) '(("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")))
+ ((zerop num-start) '(("numbers" "left")))
+ (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}"
@@ -2210,7 +2833,7 @@ CONTENTS is nil. INFO is a plist holding contextual information."
"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))
+ (org-latex--text-markup contents 'strike-through info))
;;;; Subscript
@@ -2219,17 +2842,7 @@ holding contextual information."
"Transcode a subscript or superscript object.
OBJECT is an Org object. INFO is a plist used as a communication
channel."
- (let ((in-script-p
- ;; Non-nil if object is already in a sub/superscript.
- (let ((parent object))
- (catch 'exit
- (while (setq parent (org-export-get-parent parent))
- (let ((type (org-element-type parent)))
- (cond ((memq type '(subscript superscript))
- (throw 'exit t))
- ((memq type org-element-all-elements)
- (throw 'exit nil))))))))
- (type (org-element-type object))
+ (let ((type (org-element-type object))
(output ""))
(org-element-map (org-element-contents object)
(cons 'plain-text org-element-all-objects)
@@ -2255,31 +2868,12 @@ channel."
(let ((blank (org-element-property :post-blank obj)))
(and blank (> blank 0) "\\ ")))))))
info nil org-element-recursive-objects)
- ;; Result. Do not wrap into math mode if already in a subscript
- ;; or superscript. Do not wrap into curly brackets if OUTPUT is
- ;; a single character. Also merge consecutive subscript and
- ;; superscript into the same math snippet.
- (concat (and (not in-script-p)
- (let ((prev (org-export-get-previous-element object info)))
- (or (not prev)
- (not (eq (org-element-type prev)
- (if (eq type 'subscript) 'superscript
- 'subscript)))
- (let ((blank (org-element-property :post-blank prev)))
- (and blank (> blank 0)))))
- "$")
- (if (eq (org-element-type object) 'subscript) "_" "^")
+ ;; Result. Do not wrap into curly brackets if OUTPUT is a single
+ ;; character.
+ (concat (if (eq (org-element-type object) 'subscript) "_" "^")
(and (> (length output) 1) "{")
output
- (and (> (length output) 1) "}")
- (and (not in-script-p)
- (or (let ((blank (org-element-property :post-blank object)))
- (and blank (> blank 0)))
- (not (eq (org-element-type
- (org-export-get-next-element object info))
- (if (eq type 'subscript) 'superscript
- 'subscript))))
- "$"))))
+ (and (> (length output) 1) "}"))))
(defun org-latex-subscript (subscript contents info)
"Transcode a SUBSCRIPT object from Org to LaTeX.
@@ -2316,7 +2910,7 @@ contextual information."
;; "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)
- org-latex-default-table-mode)))
+ (plist-get info :latex-default-table-mode))))
(cond
;; Case 1: Verbatim table.
((string= type "verbatim")
@@ -2376,14 +2970,15 @@ This function assumes TABLE has `org' as its `:type' property and
(alignment (org-latex--align-string table info))
;; Determine environment for the table: longtable, tabular...
(table-env (or (plist-get attr :environment)
- org-latex-default-table-environment))
+ (plist-get info :latex-default-table-environment)))
;; If table is a float, determine environment: table, table*
;; or sidewaystable.
(float-env (unless (member table-env '("longtable" "longtabu"))
(let ((float (plist-get attr :float)))
(cond
((and (not float) (plist-member attr :float)) nil)
- ((string= float "sidewaystable") "sidewaystable")
+ ((or (string= float "sidewaystable")
+ (string= float "sideways")) "sidewaystable")
((string= float "multicolumn") "table*")
((or float
(org-element-property :caption table)
@@ -2392,23 +2987,26 @@ This function assumes TABLE has `org' as its `:type' property and
;; Extract others display options.
(fontsize (let ((font (plist-get attr :font)))
(and font (concat font "\n"))))
- (width (plist-get attr :width))
+ ;; "tabular" environment doesn't allow to define a width.
+ (width (and (not (equal table-env "tabular")) (plist-get attr :width)))
(spreadp (plist-get attr :spread))
- (placement (or (plist-get attr :placement)
- (format "[%s]" org-latex-default-figure-position)))
+ (placement
+ (or (plist-get attr :placement)
+ (format "[%s]" (plist-get info :latex-default-figure-position))))
(centerp (if (plist-member attr :center) (plist-get attr :center)
- org-latex-tables-centered)))
+ (plist-get info :latex-tables-centered)))
+ (caption-above-p (org-latex--caption-above-p table info)))
;; Prepare the final format string for the table.
(cond
;; Longtable.
((equal "longtable" table-env)
(concat (and fontsize (concat "{" fontsize))
(format "\\begin{longtable}{%s}\n" alignment)
- (and org-latex-table-caption-above
+ (and caption-above-p
(org-string-nw-p caption)
(concat caption "\\\\\n"))
contents
- (and (not org-latex-table-caption-above)
+ (and (not caption-above-p)
(org-string-nw-p caption)
(concat caption "\\\\\n"))
"\\end{longtable}\n"
@@ -2421,11 +3019,11 @@ This function assumes TABLE has `org' as its `:type' property and
(format " %s %s "
(if spreadp "spread" "to") width) "")
alignment)
- (and org-latex-table-caption-above
+ (and caption-above-p
(org-string-nw-p caption)
(concat caption "\\\\\n"))
contents
- (and (not org-latex-table-caption-above)
+ (and (not caption-above-p)
(org-string-nw-p caption)
(concat caption "\\\\\n"))
"\\end{longtabu}\n"
@@ -2434,9 +3032,15 @@ This function assumes TABLE has `org' as its `:type' property and
(t (concat (cond
(float-env
(concat (format "\\begin{%s}%s\n" float-env placement)
- (if org-latex-table-caption-above caption "")
+ (if caption-above-p caption "")
(when centerp "\\centering\n")
fontsize))
+ ((and (not float-env) caption)
+ (concat
+ (and centerp "\\begin{center}\n" )
+ (if caption-above-p caption "")
+ (cond ((and fontsize centerp) fontsize)
+ (fontsize (concat "{" fontsize)))))
(centerp (concat "\\begin{center}\n" fontsize))
(fontsize (concat "{" fontsize)))
(cond ((equal "tabu" table-env)
@@ -2454,8 +3058,13 @@ This function assumes TABLE has `org' as its `:type' property and
table-env)))
(cond
(float-env
- (concat (if org-latex-table-caption-above "" caption)
+ (concat (if caption-above-p "" (concat "\n" caption))
(format "\n\\end{%s}" float-env)))
+ ((and (not float-env) caption)
+ (concat
+ (if caption-above-p "" (concat "\n" caption))
+ (and centerp "\n\\end{center}")
+ (and fontsize (not centerp) "}")))
(centerp "\n\\end{center}")
(fontsize "}")))))))
@@ -2492,7 +3101,7 @@ property."
(incf n)
(unless (= n 2) (setq output (replace-match "" nil nil output))))))
(let ((centerp (if (plist-member attr :center) (plist-get attr :center)
- org-latex-tables-centered)))
+ (plist-get info :latex-tables-centered))))
(if (not centerp) output
(format "\\begin{center}\n%s\n\\end{center}" output))))))
@@ -2503,12 +3112,10 @@ 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* ((caption (org-latex--caption/label-string table info))
- (attr (org-export-read-attribute :attr_latex table))
- (inlinep (equal (plist-get attr :mode) "inline-math"))
+`inline-math' or `math' as its `:mode' attribute."
+ (let* ((attr (org-export-read-attribute :attr_latex table))
(env (or (plist-get attr :environment)
- org-latex-default-table-environment))
+ (plist-get info :latex-default-table-environment)))
(contents
(mapconcat
(lambda (row)
@@ -2519,38 +3126,18 @@ This function assumes TABLE has `org' as its `:type' property and
(mapconcat
(lambda (cell)
(substring (org-element-interpret-data cell) 0 -1))
- (org-element-map row 'table-cell 'identity info) "&")
+ (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) ""))
- ;; Variables related to math clusters (contiguous math tables
- ;; of the same type).
- (mode (org-export-read-attribute :attr_latex table :mode))
- (prev (org-export-get-previous-element table info))
- (next (org-export-get-next-element table info))
- (same-mode-p
- (lambda (table)
- ;; Non-nil when TABLE has the same mode as current table.
- (string= (or (org-export-read-attribute :attr_latex table :mode)
- org-latex-default-table-mode)
- mode))))
+ (org-element-map table 'table-row #'identity info) "")))
(concat
- ;; Opening string. If TABLE is in the middle of a table cluster,
- ;; do not insert any.
- (cond ((and prev
- (eq (org-element-type prev) 'table)
- (memq (org-element-property :post-blank prev) '(0 nil))
- (funcall same-mode-p prev))
- nil)
- (inlinep "\\(")
- ((org-string-nw-p caption) (concat "\\begin{equation}\n" caption))
- (t "\\["))
;; Prefix.
- (or (plist-get attr :math-prefix) "")
+ (plist-get attr :math-prefix)
;; Environment. Also treat special cases.
- (cond ((equal env "array")
- (let ((align (org-latex--align-string table info)))
- (format "\\begin{array}{%s}\n%s\\end{array}" align contents)))
+ (cond ((member env '("array" "tabular"))
+ (let ((align (make-string
+ (cdr (org-export-table-dimensions table info)) ?c)))
+ (format "\\begin{%s}{%s}\n%s\\end{%s}" env align contents env)))
((assoc env org-latex-table-matrix-macros)
(format "\\%s%s{\n%s}"
env
@@ -2558,28 +3145,7 @@ This function assumes TABLE has `org' as its `:type' property and
contents))
(t (format "\\begin{%s}\n%s\\end{%s}" env contents env)))
;; Suffix.
- (or (plist-get attr :math-suffix) "")
- ;; Closing string. If TABLE is in the middle of a table cluster,
- ;; do not insert any. If it closes such a cluster, be sure to
- ;; close the cluster with a string matching the opening string.
- (cond ((and next
- (eq (org-element-type next) 'table)
- (memq (org-element-property :post-blank table) '(0 nil))
- (funcall same-mode-p next))
- nil)
- (inlinep "\\)")
- ;; Find cluster beginning to know which environment to use.
- ((let ((cluster-beg table) prev)
- (while (and (setq prev (org-export-get-previous-element
- cluster-beg info))
- (memq (org-element-property :post-blank prev)
- '(0 nil))
- (funcall same-mode-p prev))
- (setq cluster-beg prev))
- (and (or (org-element-property :caption cluster-beg)
- (org-element-property :name cluster-beg))
- "\n\\end{equation}")))
- (t "\\]")))))
+ (plist-get attr :math-suffix))))
;;;; Table Cell
@@ -2588,16 +3154,18 @@ This function assumes TABLE has `org' as its `:type' property and
"Transcode a TABLE-CELL element from Org to LaTeX.
CONTENTS is the cell contents. INFO is a plist used as
a communication channel."
- (concat (if (and contents
- org-latex-table-scientific-notation
- (string-match orgtbl-exp-regexp contents))
- ;; Use appropriate format string for scientific
- ;; notation.
- (format org-latex-table-scientific-notation
- (match-string 1 contents)
- (match-string 2 contents))
- contents)
- (when (org-export-get-next-element table-cell info) " & ")))
+ (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
@@ -2606,44 +3174,62 @@ a communication channel."
"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."
- ;; Rules are ignored since table separators are deduced from
- ;; borders of the current row.
- (when (eq (org-element-property :type table-row) 'standard)
- (let* ((attr (org-export-read-attribute :attr_latex
- (org-export-get-parent table-row)))
- (longtablep (member (or (plist-get attr :environment)
- org-latex-default-table-environment)
- '("longtable" "longtabu")))
- (booktabsp (if (plist-member attr :booktabs)
- (plist-get attr :booktabs)
- org-latex-tables-booktabs))
- ;; TABLE-ROW's borders are extracted from its first cell.
- (borders (org-export-table-cell-borders
- (car (org-element-contents table-row)) info)))
+ (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.
- (cond ((and booktabsp (memq 'top borders)) "\\toprule\n")
- ((and (memq 'top borders) (memq 'above borders)) "\\hline\n"))
+ (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.
+ ;; Special case for long tables. Define header and footers.
((and longtablep (org-export-table-row-ends-header-p table-row info))
- (format "%s
+ (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}{Continued on next page} \\\\
+%s\\multicolumn{%d}{r}{%s} \\\\
\\endfoot
\\endlastfoot"
- (if booktabsp "\\midrule" "\\hline")
- (if booktabsp "\\midrule" "\\hline")
- ;; Number of columns.
- (cdr (org-export-table-dimensions
- (org-export-get-parent-table table-row) info))))
+ (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 (memq 'bottom borders)) "\\bottomrule")
- ((and (memq 'bottom borders) (memq 'below borders)) "\\hline")
- ((memq 'below borders) (if booktabsp "\\midrule" "\\hline")))))))
+ ((and booktabsp (not (org-export-get-next-element table-row info)))
+ "\\bottomrule"))))))
;;;; Target
@@ -2652,8 +3238,7 @@ a communication channel."
"Transcode a TARGET object from Org to LaTeX.
CONTENTS is nil. INFO is a plist holding contextual
information."
- (format "\\label{%s}"
- (org-export-solidify-link-text (org-element-property :value target))))
+ (format "\\label{%s}" (org-latex--label target info)))
;;;; Timestamp
@@ -2662,13 +3247,14 @@ information."
"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)))
- (case (org-element-property :type timestamp)
- ((active active-range) (format org-latex-active-timestamp-format value))
- ((inactive inactive-range)
- (format org-latex-inactive-timestamp-format value))
- (otherwise (format org-latex-diary-timestamp-format value)))))
+ (let ((value (org-latex-plain-text (org-timestamp-translate timestamp) info)))
+ (format
+ (plist-get info
+ (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
@@ -2677,7 +3263,7 @@ information."
"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))
+ (org-latex--text-markup contents 'underline info))
;;;; Verbatim
@@ -2686,7 +3272,8 @@ holding contextual information."
"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))
+ (org-latex--text-markup
+ (org-element-property :value verbatim) 'verbatim info))
;;;; Verse Block
@@ -2701,16 +3288,15 @@ contextual information."
;; character and change each white space at beginning of a line
;; into a space of 1 em. Also change each blank line with
;; a vertical space of 1 em.
- (progn
- (setq contents (replace-regexp-in-string
- "^ *\\\\\\\\$" "\\\\vspace*{1em}"
- (replace-regexp-in-string
- "\\(\\\\\\\\\\)?[ \t]*\n" " \\\\\\\\\n" contents)))
- (while (string-match "^[ \t]+" contents)
- (let ((new-str (format "\\hspace*{%dem}"
- (length (match-string 0 contents)))))
- (setq contents (replace-match new-str nil t contents))))
- (format "\\begin{verse}\n%s\\end{verse}" contents))))
+ (format "\\begin{verse}\n%s\\end{verse}"
+ (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))
+ info))
@@ -2845,7 +3431,8 @@ Return PDF file name or an error if it couldn't be produced."
(default-directory (if (file-name-absolute-p texfile)
(file-name-directory full-name)
default-directory))
- errors)
+ (time (current-time))
+ warnings)
(unless snippet (message (format "Processing LaTeX file %s..." texfile)))
(save-window-excursion
(cond
@@ -2858,59 +3445,60 @@ Return PDF file name or an error if it couldn't be produced."
((consp org-latex-pdf-process)
(let ((outbuf (and (not snippet)
(get-buffer-create "*Org PDF LaTeX Output*"))))
- (mapc
- (lambda (command)
- (shell-command
+ (dolist (command org-latex-pdf-process)
+ (shell-command
+ (replace-regexp-in-string
+ "%b" (shell-quote-argument base-name)
(replace-regexp-in-string
- "%b" (shell-quote-argument base-name)
+ "%f" (shell-quote-argument full-name)
(replace-regexp-in-string
- "%f" (shell-quote-argument full-name)
- (replace-regexp-in-string
- "%o" (shell-quote-argument out-dir) command t t) t t) t t)
- outbuf))
- org-latex-pdf-process)
+ "%o" (shell-quote-argument out-dir) command t t) t t) t t)
+ outbuf))
;; Collect standard errors from output buffer.
- (setq errors (and (not snippet) (org-latex--collect-errors outbuf)))))
+ (setq warnings (and (not snippet)
+ (org-latex--collect-warnings outbuf)))))
(t (error "No valid command to process to PDF")))
(let ((pdffile (concat out-dir base-name ".pdf")))
;; Check for process failure. Provide collected errors if
;; possible.
- (if (not (file-exists-p pdffile))
- (error (concat (format "PDF file %s wasn't produced" pdffile)
- (when errors (concat ": " errors))))
+ (if (or (not (file-exists-p pdffile))
+ (time-less-p (nth 5 (file-attributes pdffile)) time))
+ (error (format "PDF file %s wasn't produced" pdffile))
;; Else remove log files, when specified, and signal end of
;; process to user, along with any error encountered.
- (when (and (not snippet) org-latex-remove-logfiles)
- (dolist (file (directory-files
- out-dir t
- (concat (regexp-quote base-name)
- "\\(?:\\.[0-9]+\\)?"
- "\\."
- (regexp-opt org-latex-logfiles-extensions))))
- (delete-file file)))
- (message (concat "Process completed"
- (if (not errors) "."
- (concat " with errors: " errors)))))
+ (unless snippet
+ (when org-latex-remove-logfiles
+ (dolist (file (directory-files
+ out-dir t
+ (concat (regexp-quote base-name)
+ "\\(?:\\.[0-9]+\\)?"
+ "\\."
+ (regexp-opt org-latex-logfiles-extensions))))
+ (delete-file file)))
+ (message (concat "PDF file produced"
+ (cond
+ ((eq warnings 'error) " with errors.")
+ (warnings (concat " with warnings: " warnings))
+ (t "."))))))
;; Return output file name.
pdffile))))
-(defun org-latex--collect-errors (buffer)
- "Collect some kind of errors from \"pdflatex\" command output.
-
-BUFFER is the buffer containing output.
-
-Return collected error types as a string, or nil if there was
-none."
+(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)
- (let ((case-fold-search t)
- (errors ""))
- (dolist (latex-error org-latex-known-errors)
- (when (save-excursion (re-search-forward (car latex-error) nil t))
- (setq errors (concat errors " " (cdr latex-error)))))
- (and (org-string-nw-p errors) (org-trim errors)))))))
+ (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)