dotemacs

My Emacs configuration
git clone git://git.entf.net/dotemacs
Log | Files | Refs | LICENSE

ob-latex.el (10918B)


      1 ;;; ob-latex.el --- Babel Functions for LaTeX        -*- lexical-binding: t; -*-
      2 
      3 ;; Copyright (C) 2009-2023 Free Software Foundation, Inc.
      4 
      5 ;; Author: Eric Schulte
      6 ;; Keywords: literate programming, reproducible research
      7 ;; URL: https://orgmode.org
      8 
      9 ;; This file is part of GNU Emacs.
     10 
     11 ;; GNU Emacs is free software: you can redistribute it and/or modify
     12 ;; it under the terms of the GNU General Public License as published by
     13 ;; the Free Software Foundation, either version 3 of the License, or
     14 ;; (at your option) any later version.
     15 
     16 ;; GNU Emacs is distributed in the hope that it will be useful,
     17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
     18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     19 ;; GNU General Public License for more details.
     20 
     21 ;; You should have received a copy of the GNU General Public License
     22 ;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
     23 
     24 ;;; Commentary:
     25 
     26 ;; Org-Babel support for evaluating LaTeX source code.
     27 ;;
     28 ;; Currently on evaluation this returns raw LaTeX code, unless a :file
     29 ;; header argument is given in which case small png or pdf files will
     30 ;; be created directly form the latex source code.
     31 
     32 ;;; Code:
     33 
     34 (require 'org-macs)
     35 (org-assert-version)
     36 
     37 (require 'ob)
     38 (require 'org-macs)
     39 
     40 (declare-function org-create-formula-image "org" (string tofile options buffer &optional type))
     41 (declare-function org-latex-compile "ox-latex" (texfile &optional snippet))
     42 (declare-function org-latex-guess-inputenc "ox-latex" (header))
     43 (declare-function org-splice-latex-header "org" (tpl def-pkg pkg snippets-p &optional extra))
     44 (declare-function org-at-heading-p "org" (&optional _))
     45 (declare-function org-back-to-heading "org" (&optional invisible-ok))
     46 (declare-function org-next-visible-heading "org" (arg))
     47 
     48 (defvar org-babel-tangle-lang-exts)
     49 (add-to-list 'org-babel-tangle-lang-exts '("latex" . "tex"))
     50 
     51 (defvar org-format-latex-header)	  ; From org.el
     52 (defvar org-format-latex-options)	  ; From org.el
     53 (defvar org-latex-default-packages-alist) ; From org.el
     54 (defvar org-latex-packages-alist)	  ; From org.el
     55 
     56 (defvar org-babel-default-header-args:latex
     57   '((:results . "latex") (:exports . "results"))
     58   "Default arguments to use when evaluating a LaTeX source block.")
     59 
     60 (defconst org-babel-header-args:latex
     61   '((border	  . :any)
     62     (fit          . :any)
     63     (imagemagick  . ((nil t)))
     64     (iminoptions  . :any)
     65     (imoutoptions . :any)
     66     (packages     . :any)
     67     (pdfheight    . :any)
     68     (pdfpng       . :any)
     69     (pdfwidth     . :any)
     70     (headers      . :any)
     71     (buffer       . ((yes no))))
     72   "LaTeX-specific header arguments.")
     73 
     74 (defcustom org-babel-latex-htlatex "htlatex"
     75   "The htlatex command to enable conversion of LaTeX to SVG or HTML."
     76   :group 'org-babel
     77   :type 'string)
     78 
     79 (defcustom org-babel-latex-preamble
     80   (lambda (_)
     81     "\\documentclass[preview]{standalone}
     82 \\def\\pgfsysdriver{pgfsys-tex4ht.def}
     83 ")
     84   "Closure which evaluates at runtime to the LaTeX preamble.
     85 
     86 It takes 1 argument which is the parameters of the source block."
     87   :group 'org-babel
     88   :type 'function)
     89 
     90 (defcustom org-babel-latex-begin-env
     91   (lambda (_)
     92     "\\begin{document}")
     93   "Function that evaluates to the begin part of the document environment.
     94 
     95 It takes 1 argument which is the parameters of the source block.
     96 This allows adding additional code that will be ignored when
     97 exporting the literal LaTeX source."
     98   :group 'org-babel
     99   :type 'function)
    100 
    101 (defcustom org-babel-latex-end-env
    102   (lambda (_)
    103     "\\end{document}")
    104   "Closure which evaluates at runtime to the end part of the document environment.
    105 
    106 It takes 1 argument which is the parameters of the source block.
    107 This allows adding additional code that will be ignored when
    108 exporting the literal LaTeX source."
    109   :group 'org-babel
    110   :type 'function)
    111 
    112 (defcustom org-babel-latex-pdf-svg-process
    113   "inkscape \
    114 --pdf-poppler \
    115 --export-area-drawing \
    116 --export-text-to-path \
    117 --export-plain-svg \
    118 --export-filename=%O \
    119 %f"
    120   "Command to convert a PDF file to an SVG file."
    121   :group 'org-babel
    122   :type 'string
    123   :package-version '(Org . "9.6"))
    124 
    125 (defcustom org-babel-latex-htlatex-packages
    126   '("[usenames]{color}" "{tikz}" "{color}" "{listings}" "{amsmath}")
    127   "Packages to use for htlatex export."
    128   :group 'org-babel
    129   :type '(repeat (string)))
    130 
    131 (defun org-babel-expand-body:latex (body params)
    132   "Expand BODY according to PARAMS, return the expanded body."
    133   (mapc (lambda (pair) ;; replace variables
    134           (setq body
    135                 (replace-regexp-in-string
    136                  (regexp-quote (format "%S" (car pair)))
    137                  (if (stringp (cdr pair))
    138                      (cdr pair) (format "%S" (cdr pair)))
    139                  body)))
    140 	(org-babel--get-vars params))
    141   (org-trim body))
    142 
    143 (defun org-babel-execute:latex (body params)
    144   "Execute a block of Latex code with Babel.
    145 This function is called by `org-babel-execute-src-block'."
    146   (setq body (org-babel-expand-body:latex body params))
    147   (if (cdr (assq :file params))
    148       (let* ((out-file (cdr (assq :file params)))
    149 	     (extension (file-name-extension out-file))
    150 	     (tex-file (org-babel-temp-file "latex-" ".tex"))
    151 	     (border (cdr (assq :border params)))
    152 	     (imagemagick (cdr (assq :imagemagick params)))
    153 	     (im-in-options (cdr (assq :iminoptions params)))
    154 	     (im-out-options (cdr (assq :imoutoptions params)))
    155 	     (fit (or (cdr (assq :fit params)) border))
    156 	     (height (and fit (cdr (assq :pdfheight params))))
    157 	     (width (and fit (cdr (assq :pdfwidth params))))
    158 	     (headers (cdr (assq :headers params)))
    159 	     (in-buffer (not (string= "no" (cdr (assq :buffer params)))))
    160 	     (org-latex-packages-alist
    161 	      (append (cdr (assq :packages params)) org-latex-packages-alist)))
    162         (cond
    163          ((and (string-suffix-p ".png" out-file) (not imagemagick))
    164           (let ((org-format-latex-header
    165 		 (concat org-format-latex-header "\n"
    166 			 (mapconcat #'identity headers "\n"))))
    167 	    (org-create-formula-image
    168              body out-file org-format-latex-options in-buffer)))
    169 	 ((string= "svg" extension)
    170 	  (with-temp-file tex-file
    171 	    (insert (concat (funcall org-babel-latex-preamble params)
    172 			    (mapconcat #'identity headers "\n")
    173 			    (funcall org-babel-latex-begin-env params)
    174 			    body
    175 			    (funcall org-babel-latex-end-env params))))
    176 	  (let ((tmp-pdf (org-babel-latex-tex-to-pdf tex-file)))
    177             (let* ((log-buf (get-buffer-create "*Org Babel LaTeX Output*"))
    178                    (err-msg "org babel latex failed")
    179                    (img-out (org-compile-file
    180 	                     tmp-pdf
    181                              (list org-babel-latex-pdf-svg-process)
    182                              extension err-msg log-buf)))
    183               (shell-command (format "mv %s %s" img-out out-file)))))
    184          ((string-suffix-p ".tikz" out-file)
    185 	  (when (file-exists-p out-file) (delete-file out-file))
    186 	  (with-temp-file out-file
    187 	    (insert body)))
    188 	 ((and (string= "html" extension)
    189 	       (executable-find org-babel-latex-htlatex))
    190 	  ;; TODO: this is a very different way of generating the
    191 	  ;; frame latex document than in the pdf case.  Ideally, both
    192 	  ;; would be unified.  This would prevent bugs creeping in
    193 	  ;; such as the one fixed on Aug 16 2014 whereby :headers was
    194 	  ;; not included in the SVG/HTML case.
    195 	  (with-temp-file tex-file
    196 	    (insert (concat
    197 		     "\\documentclass[preview]{standalone}
    198 \\def\\pgfsysdriver{pgfsys-tex4ht.def}
    199 "
    200 		     (mapconcat (lambda (pkg)
    201 				  (concat "\\usepackage" pkg))
    202 				org-babel-latex-htlatex-packages
    203 				"\n")
    204 		     (if headers
    205 			 (concat "\n"
    206 				 (if (listp headers)
    207 				     (mapconcat #'identity headers "\n")
    208 				   headers) "\n")
    209 		       "")
    210 		     "\\begin{document}"
    211 		     body
    212 		     "\\end{document}")))
    213 	  (when (file-exists-p out-file) (delete-file out-file))
    214 	  (let ((default-directory (file-name-directory tex-file)))
    215 	    (shell-command (format "%s %s" org-babel-latex-htlatex tex-file)))
    216 	  (cond
    217 	   ((file-exists-p (concat (file-name-sans-extension tex-file) "-1.svg"))
    218 	    (if (string-suffix-p ".svg" out-file)
    219 		(progn
    220 		  (shell-command "pwd")
    221 		  (shell-command (format "mv %s %s"
    222 					 (concat (file-name-sans-extension tex-file) "-1.svg")
    223 					 out-file)))
    224 	      (error "SVG file produced but HTML file requested")))
    225 	   ((file-exists-p (concat (file-name-sans-extension tex-file) ".html"))
    226 	    (if (string-suffix-p ".html" out-file)
    227 		(shell-command "mv %s %s"
    228 			       (concat (file-name-sans-extension tex-file)
    229 				       ".html")
    230 			       out-file)
    231 	      (error "HTML file produced but SVG file requested")))))
    232 	 ((or (string= "pdf" extension) imagemagick)
    233 	  (with-temp-file tex-file
    234 	    (require 'ox-latex)
    235 	    (insert
    236 	     (org-latex-guess-inputenc
    237 	      (org-splice-latex-header
    238 	       org-format-latex-header
    239 	       (delq
    240 		nil
    241 		(mapcar
    242 		 (lambda (el)
    243 		   (unless (and (listp el) (string= "hyperref" (cadr el)))
    244 		     el))
    245 		 org-latex-default-packages-alist))
    246 	       org-latex-packages-alist
    247 	       nil))
    248 	     (if fit "\n\\usepackage[active, tightpage]{preview}\n" "")
    249 	     (if border (format "\\setlength{\\PreviewBorder}{%s}" border) "")
    250 	     (if height (concat "\n" (format "\\pdfpageheight %s" height)) "")
    251 	     (if width  (concat "\n" (format "\\pdfpagewidth %s" width))   "")
    252 	     (if headers
    253 		 (concat "\n"
    254 			 (if (listp headers)
    255 			     (mapconcat #'identity headers "\n")
    256 			   headers) "\n")
    257 	       "")
    258 	     (if fit
    259 		 (concat "\n\\begin{document}\n\\begin{preview}\n" body
    260 			 "\n\\end{preview}\n\\end{document}\n")
    261 	       (concat "\n\\begin{document}\n" body "\n\\end{document}\n"))))
    262           (when (file-exists-p out-file) (delete-file out-file))
    263 	  (let ((transient-pdf-file (org-babel-latex-tex-to-pdf tex-file)))
    264 	    (cond
    265 	     ((string= "pdf" extension)
    266 	      (rename-file transient-pdf-file out-file))
    267 	     (imagemagick
    268 	      (org-babel-latex-convert-pdf
    269 	       transient-pdf-file out-file im-in-options im-out-options)
    270 	      (when (file-exists-p transient-pdf-file)
    271 		(delete-file transient-pdf-file)))
    272 	     (t
    273 	      (error "Can not create %s files, please specify a .png or .pdf file or try the :imagemagick header argument"
    274 		     extension))))))
    275         nil) ;; signal that output has already been written to file
    276     body))
    277 
    278 (defun org-babel-latex-convert-pdf (pdffile out-file im-in-options im-out-options)
    279   "Generate a file from a pdf file using imagemagick."
    280   (let ((cmd (concat "convert " im-in-options " " pdffile " "
    281 		     im-out-options " " out-file)))
    282     (message "Converting pdffile file %s..." cmd)
    283     (shell-command cmd)))
    284 
    285 (defun org-babel-latex-tex-to-pdf (file)
    286   "Generate a pdf file according to the contents FILE."
    287   (require 'ox-latex)
    288   (org-latex-compile file))
    289 
    290 (defun org-babel-prep-session:latex (_session _params)
    291   "Return an error because LaTeX doesn't support sessions."
    292   (error "LaTeX does not support sessions"))
    293 
    294 (provide 'ob-latex)
    295 
    296 ;;; ob-latex.el ends here