1 ;;; org-export-latex.el --- LaTeX exporter for Org-mode
2 ;; Copyright (C) 2007 Free Software Foundation, Inc.
4 ;; Author: Bastien Guerry <bzg AT altern DOT org>
5 ;; Keywords: org organizer latex export convert
6 ;; Version: $Id: org-export-latex.el,v 0.27b 2007/08/25 14:26:06 guerry Exp guerry $
7 ;; X-URL: <http://www.cognition.ens.fr/~guerry/u/org-export-latex.el>
9 ;; This file is part of GNU Emacs.
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 2, or (at your option)
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.
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs; see the file COPYING. If not, write to the
23 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24 ;; Boston, MA 02110-1301, USA.
28 ;; This library implements a LaTeX exporter for org-mode.
30 ;; Put this file into your load-path and the following into your ~/.emacs:
31 ;; (require 'org-export-latex)
33 ;; The interactive functions are similar to those of the HTML exporter:
35 ;; M-x `org-export-as-latex'
36 ;; M-x `org-export-as-latex-batch'
37 ;; M-x `org-export-as-latex-to-buffer'
38 ;; M-x `org-export-region-as-latex'
39 ;; M-x `org-replace-region-by-latex'
49 (defvar org-latex-options-plist nil
)
50 (defvar org-latex-todo-keywords-1 nil
)
51 (defvar org-latex-all-targets-regexp nil
)
52 (defvar org-latex-add-level
0)
53 (defvar org-latex-sectioning-depth
0)
55 (defvar org-latex-special-string-regexps
60 "A list of regexps to convert as special keywords.")
62 (defcustom org-export-latex-sectioning-alist
63 '((1 "\\section{%s}" "\\section*{%s}")
64 (2 "\\subsection{%s}" "\\subsection*{%s}")
65 (3 "\\subsubsection{%s}" "\\subsubsection*{%s}")
66 (4 "\\paragraph{%s}" "\\paragraph*{%s}")
67 (5 "\\subparagraph{%s}" "\\subparagraph*{%s}"))
68 "Alist of LaTeX commands for inserting sections.
69 Here is the structure of each cell:
71 \(level unnumbered-section numbered-section\)
73 The %s formatter will be replaced by the title of the section."
74 :group
'org-export-latex
77 (defcustom org-export-latex-emphasis-alist
78 '(("*" "\\textbf{%s}")
80 ("_" "\\underline{%s}")
83 "Alist of LaTeX expressions to convert emphasis fontifiers."
84 :group
'org-export-latex
87 (defcustom org-export-latex-preamble
88 "\\documentclass[11pt,a4paper]{article}
89 \\usepackage[utf8]{inputenc}
90 \\usepackage[T1]{fontenc}
91 \\usepackage{hyperref}"
92 "Preamble to be inserted at the very beginning of the LaTeX export."
93 :group
'org-export-latex
96 (defcustom org-export-latex-date-format nil
97 "Format string for \\date{...}."
98 :group
'org-export-latex
101 (defcustom org-export-latex-packages-alist nil
102 "Alist of packages to be inserted in the preamble.
103 Each cell is of the forma \( option . package \).
107 \(setq org-export-latex-packages-alist
108 '((\"french\" \"babel\"))"
109 :group
'org-export-latex
112 (defcustom org-export-latex-low-levels
'description
113 "Choice for converting sections that are below the current
114 admitted level of sectioning. This can be either nil (ignore the
115 sections), 'description (convert them as description lists) or a
116 string to be used instead of \\section{%s} (a %s for inserted the
117 headline is mandatory)."
118 :group
'org-export-latex
119 :type
'(choice (const :tag
"Ignore" nil
)
120 (symbol :tag
"Convert as descriptive list" description
)
121 (string :tag
"Use a section string" :value
"\\subparagraph{%s}")))
123 (defcustom org-export-latex-remove-from-headines
124 '(:todo t
:priority t
:tags t
)
125 "A plist of keywords to remove from headlines.
126 Non-nil means remove this keyword type from the headline.
128 Don't remove the keys, just change their values."
130 :group
'org-export-latex
)
132 (defcustom org-export-latex-quotation-marks-convention
"en"
133 "Convention for conversion of the quotation marks.
134 This value is overriden by any infile language setup."
135 :group
'org-export-latex
136 :type
'(choice (string :tag
"english" "en")
137 (string :tag
"french" "fr")))
139 (defcustom org-export-latex-image-default-option
"width=10em"
140 "Default option for images."
141 :group
'org-export-latex
144 (defcustom org-export-latex-coding-system nil
145 "Coding system for the exported LaTex file."
146 :group
'org-export-latex
147 :type
'coding-system
)
149 ;; FIXME Do we want this one?
150 ;; (defun org-export-as-latex-and-open (arg) ...)
153 (defun org-export-as-latex-batch ()
154 "Call `org-export-as-latex', may be used in batch processing as
156 --load=$HOME/lib/emacs/org.el
157 --eval \"(setq org-export-headline-levels 2)\"
158 --visit=MyFile --funcall org-export-as-latex-batch"
159 (org-export-as-latex org-export-headline-levels
'hidden
))
162 (defun org-export-as-latex-to-buffer (arg)
163 "Call `org-exort-as-latex` with output to a temporary buffer.
164 No file is created. The prefix ARG is passed through to `org-export-as-latex'."
166 (org-export-as-latex arg nil nil
"*Org LaTeX Export*")
167 (switch-to-buffer-other-window "*Org LaTeX Export*"))
170 (defun org-replace-region-by-latex (beg end
)
171 "Replace the region from BEG to END with its LaTeX export.
172 It assumes the region has `org-mode' syntax, and then convert it to
173 LaTeX. This can be used in any buffer. For example, you could
174 write an itemized list in `org-mode' syntax in an LaTeX buffer and
175 then use this command to convert it."
178 (save-window-excursion
180 (setq latex
(org-export-region-as-latex
182 (setq reg
(buffer-substring beg end
)
183 buf
(get-buffer-create "*Org tmp*"))
189 (setq latex
(org-export-region-as-latex
190 (point-min) (point-max) t
'string
)))
192 (delete-region beg end
)
196 (defun org-export-region-as-latex (beg end
&optional body-only buffer
)
197 "Convert region from BEG to END in `org-mode' buffer to LaTeX.
198 If prefix arg BODY-ONLY is set, omit file header, footer, and table of
199 contents, and only produce the region of converted text, useful for
200 cut-and-paste operations.
201 If BUFFER is a buffer or a string, use/create that buffer as a target
202 of the converted LaTeX. If BUFFER is the symbol `string', return the
203 produced LaTeX as a string and leave not buffer behind. For example,
204 a Lisp program could call this function in the following way:
206 (setq latex (org-export-region-as-latex beg end t 'string))
208 When called interactively, the output buffer is selected, and shown
209 in a window. A non-interactive call will only retunr the buffer."
211 (when (interactive-p)
212 (setq buffer
"*Org LaTeX Export*"))
213 (let ((transient-mark-mode t
) (zmacs-regions t
)
216 (set-mark (point)) ;; to activate the region
218 (setq rtn
(org-export-as-latex
221 (if (fboundp 'deactivate-mark
) (deactivate-mark))
222 (if (and (interactive-p) (bufferp rtn
))
223 (switch-to-buffer-other-window rtn
)
227 (defun org-export-as-latex (arg &optional hidden ext-plist
229 "Export current buffer to a LaTeX file."
231 ;; Make sure we have a file name when we need it.
232 (when (and (not (or to-buffer body-only
))
233 (not buffer-file-name
))
234 (if (buffer-base-buffer)
235 (org-set-local 'buffer-file-name
236 (with-current-buffer (buffer-base-buffer)
238 (error "Need a file name to be able to export")))
240 (message "Exporting to LaTeX...")
241 (org-update-radio-target-regexp)
242 (org-export-latex-set-initial-vars ext-plist
)
243 (let* ((opt-plist org-latex-options-plist
)
244 (filename (concat (file-name-as-directory
245 (org-export-directory :LaTeX ext-plist
))
246 (file-name-sans-extension
247 (file-name-nondirectory ;sans-extension
248 buffer-file-name
)) ".tex"))
249 (filename (if (equal (file-truename filename
)
250 (file-truename buffer-file-name
))
251 (concat filename
".tex")
253 (buffer (if to-buffer
255 ((eq to-buffer
'string
) (get-buffer-create
256 "*Org LaTeX Export*"))
257 (t (get-buffer-create to-buffer
)))
258 (find-file-noselect filename
)))
259 (region-p (org-region-active-p))
260 (odd org-odd-levels-only
)
261 (preamble (org-export-latex-make-preamble opt-plist
))
262 (skip (plist-get opt-plist
:skip-before-1st-heading
))
263 (text (plist-get opt-plist
:text
))
264 (first-lines (if skip
"" (org-export-latex-first-lines)))
265 (coding-system (and (boundp 'buffer-file-coding-system
)
266 buffer-file-coding-system
))
267 (coding-system-for-write (or org-export-latex-coding-system
269 (save-buffer-coding-system (or org-export-latex-coding-system
271 (region (buffer-substring
272 (if region-p
(region-beginning) (point-min))
273 (if region-p
(region-end) (point-max))))
275 ;; FIXME Use org-cleaned-string-for-export instead, only when
276 ;; everyone uses Org >5.04
277 (org-latex-cleaned-string-for-export
281 :skip-before-1st-heading nil
282 :LaTeX-fragments nil
)))
285 (unless body-only
(insert preamble
))
286 (when text
(insert (org-export-latex-content text
) "\n\n"))
287 (unless skip
(insert first-lines
))
289 ;; handle the case where the region does not begin with a section
291 (insert (with-temp-buffer
292 (insert string-for-export
)
293 (org-export-latex-first-lines))))
295 (org-export-latex-global
297 (insert string-for-export
)
298 (goto-char (point-min))
299 (re-search-forward "^\\(\\*+\\) " nil t
)
300 (let* ((asters (length (match-string 1)))
301 (level (if odd
(- asters
2) (- asters
1))))
302 (setq org-latex-add-level
303 (if odd
(1- (/ (1+ asters
) 2)) (1- asters
)))
304 (org-export-latex-parse-global level odd
))))
306 (unless body-only
(insert "\n\\end{document}"))
307 (or to-buffer
(write-file filename
))
308 (goto-char (point-min))
309 (message "Exporting to LaTeX...done")
310 (if (eq to-buffer
'string
)
311 (prog1 (buffer-substring (point-min) (point-max))
312 (kill-buffer (current-buffer)))
315 (defun org-export-latex-set-initial-vars (ext-plist)
316 "Store org local variables required for LaTeX export.
317 EXT-PLIST is an optional additional plist."
318 (setq org-latex-todo-keywords-1 org-todo-keywords-1
319 org-latex-all-targets-regexp
320 (org-make-target-link-regexp (org-all-targets))
321 org-latex-options-plist
322 (org-combine-plists (org-default-export-plist) ext-plist
323 (org-infile-export-plist))
324 org-latex-sectioning-depth
325 (let ((hl-levels (plist-get org-latex-options-plist
:headline-levels
))
326 (sec-depth (length org-export-latex-sectioning-alist
)))
327 ;; Fall back on org-export-latex-sectioning-alist length if
328 ;; headline-levels goes beyond it
329 (if (> hl-levels sec-depth
) sec-depth hl-levels
))))
331 (defun org-export-latex-make-preamble (opt-plist)
332 "Make the LaTeX preamble and return it as a string.
333 Argument OPT-PLIST is the options plist for current buffer."
334 (let ((toc (plist-get opt-plist
:table-of-contents
)))
335 (format (concat org-export-latex-preamble
348 (if org-export-latex-packages-alist
349 (mapconcat (lambda(p)
350 (if (equal "" (car p
))
351 (format "\\usepackage{%s}" (cadr p
))
352 (format "\\usepackage[%s]{%s}"
354 org-export-latex-packages-alist
"\n") "")
355 (or (plist-get opt-plist
:title
)
357 (plist-get opt-plist
:skip-before-1st-heading
))
358 (org-export-grab-title-from-buffer))
359 (and buffer-file-name
360 (file-name-sans-extension
361 (file-name-nondirectory buffer-file-name
)))
363 (if (plist-get opt-plist
:author-info
)
364 (format "\\author{%s}"
365 (or (plist-get opt-plist
:author
) user-full-name
))
366 (format "%%\\author{%s}"
367 (or (plist-get opt-plist
:author
) user-full-name
)))
368 (if (plist-get opt-plist
:timestamps
)
370 (format-time-string (or org-export-latex-date-format
371 (car org-time-stamp-formats
))))
373 (if (and (plist-get opt-plist
:section-numbers
) toc
)
374 (format "\\setcounter{tocdepth}{%s}"
375 (plist-get opt-plist
:headline-levels
)) "")
376 (if (and (plist-get opt-plist
:section-numbers
) toc
)
377 "\\tableofcontents" ""))))
379 (defun org-export-latex-first-lines (&optional comments
)
380 "Export the first lines before first headline.
381 COMMENTS is either nil to replace them with the empty string or a
382 formatting string like %%%%s if we want to comment them out."
384 (goto-char (point-min))
385 (let* ((end (if (re-search-forward "^\\*" nil t
)
386 (goto-char (match-beginning 0))
387 (goto-char (point-max)))))
388 (org-export-latex-content
389 (org-latex-cleaned-string-for-export
390 (buffer-substring (point-min) end
)
394 :skip-before-1st-heading nil
395 :LaTeX-fragments nil
)))))
397 (defun org-export-latex-parse-global (level odd
)
398 "Parse the current buffer recursively, starting at LEVEL.
399 If ODD is non-nil, assume the buffer only contains odd sections.
400 Return A list reflecting the document structure."
402 (goto-char (point-min))
403 (let* ((cnt 0) output
404 (depth org-latex-sectioning-depth
))
405 (while (re-search-forward
406 (concat "^\\(\\(?:\\*\\)\\{"
407 (number-to-string (+ (if odd
2 1) level
))
409 ;; make sure that there is no upper heading
414 (concat "^\\(\\(?:\\*\\)\\{"
415 (number-to-string level
)
416 "\\}\\) \\(.*\\)$") nil t
)))) t
)
418 (let* ((pos (match-beginning 0))
419 (heading (match-string 2))
420 (nlevel (if odd
(/ (+ 3 level
) 2) (1+ level
))))
425 (if (re-search-forward
426 (concat "^\\(\\(?:\\*\\)\\{"
427 (number-to-string (+ (if odd
2 1) level
))
428 "\\}\\) \\(.*\\)$") nil t
)
431 (goto-char (point-min))
439 `(heading .
,heading
)
440 `(content .
,(org-export-latex-parse-content))
441 `(subcontent .
,(org-export-latex-parse-subcontent
446 (defun org-export-latex-parse-content ()
447 "Extract the content of a section."
449 (end (if (re-search-forward "^\\(\\*\\)+ .*$" nil t
)
450 (progn (beginning-of-line) (point))
452 (buffer-substring beg end
)))
454 (defun org-export-latex-parse-subcontent (level odd
)
455 "Extract the subcontent of a section at LEVEL.
456 If ODD Is non-nil, assume subcontent only contains odd sections."
457 (if (not (re-search-forward
458 (concat "^\\(\\(?:\\*\\)\\{"
459 (number-to-string (+ (if odd
4 2) level
))
462 nil
; subcontent is nil
463 (org-export-latex-parse-global (+ (if odd
2 1) level
) odd
)))
465 (defun org-export-latex-global (content)
466 "Export CONTENT to LaTeX.
467 CONTENT is an element of the list produced by
468 `org-export-latex-parse-global'."
469 (if (eq (car content
) 'subcontent
)
470 (mapc 'org-export-latex-sub
(cdr content
))
471 (org-export-latex-sub (car content
))))
473 (defun org-export-latex-sub (subcontent)
474 "Export the list SUBCONTENT to LaTeX.
475 SUBCONTENT is an alist containing information about the headline
477 (mapc (lambda(x) (org-export-latex-subcontent x
)) subcontent
))
479 (defun org-export-latex-subcontent (subcontent)
480 "Export each cell of SUBCONTENT to LaTeX."
481 (let ((heading (org-export-latex-fontify-headline
482 (cdr (assoc 'heading subcontent
))))
483 (level (- (cdr (assoc 'level subcontent
))
484 org-latex-add-level
))
485 (occur (number-to-string (cdr (assoc 'occur subcontent
))))
486 (content (cdr (assoc 'content subcontent
)))
487 (subcontent (cadr (assoc 'subcontent subcontent
)))
488 (num (plist-get org-latex-options-plist
:section-numbers
)))
491 ((<= level org-latex-sectioning-depth
)
492 (let ((sec (assoc level org-export-latex-sectioning-alist
)))
493 (insert (format (if num
(cadr sec
) (caddr sec
)) heading
) "\n"))
494 (insert (org-export-latex-content content
))
495 (cond ((stringp subcontent
) (insert subcontent
))
496 ((listp subcontent
) (org-export-latex-sub subcontent
))))
497 ;; At a level under the hl option: we can drop this subsection
498 ((> level org-latex-sectioning-depth
)
499 (cond ((eq org-export-latex-low-levels
'description
)
500 (insert (format "\\begin{description}\n\n\\item[%s]\n\n" heading
))
501 (insert (org-export-latex-content content
))
502 (cond ((stringp subcontent
) (insert subcontent
))
503 ((listp subcontent
) (org-export-latex-sub subcontent
)))
504 (insert "\\end{description}\n"))
505 ((stringp org-export-latex-low-levels
)
506 (insert (format org-export-latex-low-levels heading
) "\n")
507 (insert (org-export-latex-content content
))
508 (cond ((stringp subcontent
) (insert subcontent
))
509 ((listp subcontent
) (org-export-latex-sub subcontent
)))))))))
511 (defun org-export-latex-keywords-maybe (remove-list)
512 "Maybe remove keywords depending on rules in REMOVE-LIST."
513 (goto-char (point-min))
514 (let ((re-todo (mapconcat 'identity org-latex-todo-keywords-1
"\\|")))
515 ;; convert TODO keywords
516 (when (re-search-forward (concat "^\\(" re-todo
"\\)") nil t
)
517 (if (plist-get remove-list
:todo
)
519 (replace-match (format "\\texttt{%s}" (match-string 1)) t t
)))
520 ;; convert priority string
521 (when (re-search-forward "\\[\\\\#.\\]" nil t
)
522 (if (plist-get remove-list
:priority
)
524 (replace-match (format "\\texttt{%s}" (match-string 0)) t t
)))
526 (when (re-search-forward "\\(:[a-zA-Z0-9]+\\)+:" nil t
)
527 (if (or (not org-export-with-tags
)
528 (plist-get remove-list
:tags
))
530 (replace-match (format "\\texttt{%s}" (match-string 0)) t t
)))))
532 (defun org-export-latex-fontify-headline (headline)
533 "Fontify special words in a HEADLINE."
535 ;; FIXME: org-inside-LaTeX-fragment-p doesn't work when the $...$ is at
536 ;; the beginning of the buffer - inserting "\n" is safe here though.
537 (insert "\n" headline
)
538 (goto-char (point-min))
539 (org-export-latex-special-chars
540 (plist-get org-latex-options-plist
:sub-superscript
))
541 (when (plist-get org-latex-options-plist
:emphasize
)
542 (org-export-latex-fontify))
543 (org-export-latex-keywords-maybe
544 org-export-latex-remove-from-headines
)
545 (org-export-latex-links)
546 (org-trim (buffer-substring-no-properties (point-min) (point-max)))))
548 (defun org-export-latex-content (content)
549 "Convert CONTENT string to LaTeX."
552 (org-export-latex-quotation-marks)
553 (org-export-latex-special-chars
554 (plist-get org-latex-options-plist
:sub-superscript
))
555 (when (plist-get org-latex-options-plist
:emphasize
)
556 (org-export-latex-fontify))
557 (org-export-latex-links)
558 (org-export-latex-keywords)
559 (org-export-latex-itemize)
560 (org-export-latex-enumerate)
561 (org-export-latex-tables
562 (plist-get org-latex-options-plist
:tables
))
563 (org-export-latex-fixed-width
564 (plist-get org-latex-options-plist
:fixed-width
))
565 (org-export-fix-invisible-strings)
566 (buffer-substring (point-min) (point-max))))
568 (defun org-export-fix-invisible-strings ()
569 "Comment out (INVISIBLE) warnings."
570 (goto-char (point-min))
571 (while (re-search-forward "(INVISIBLE)" nil t
)
572 (replace-match "%\\&")))
574 (defun org-export-latex-quotation-marks ()
575 "Export question marks depending on language conventions.
576 Local definition of the language overrides
577 `org-export-latex-quotation-marks-convention' which overrides
578 `org-export-default-language'."
579 (let* ((lang (or (plist-get org-latex-options-plist
:language
)
580 org-export-latex-quotation-marks-convention
))
581 (quote-rpl (if (equal lang
"fr")
582 '(("\\(\\s-\\)\"" "«~")
583 ("\\(\\S-\\)\"" "~»")
585 '(("\\(\\s-\\)\"" "``")
586 ("\\(\\S-\\)\"" "''")
587 ("\\(\\s-\\)'" "`")))))
588 (mapc (lambda(l) (goto-char (point-min))
589 (while (re-search-forward (car l
) nil t
)
590 (let ((rpl (concat (match-string 1) (cadr l
))))
591 (org-latex-protect rpl
)
593 (replace-match rpl t t
))))) quote-rpl
)))
595 ;; | chars/string in Org | normal environment | math environment |
596 ;; |-----------------------+-----------------------+-----------------------|
597 ;; | & # % $ | \& \# \% \$ | \& \# \% \$ |
598 ;; | { } _ ^ \ | \ { \ } \_ \^ \\ | { } _ ^ \ |
599 ;; |-----------------------+-----------------------+-----------------------|
600 ;; | a_b and a^b | $a_b$ and $a^b$ | a_b and a^b |
601 ;; | a_abc and a_{abc} | $a_a$bc and $a_{abc}$ | a_abc and a_{abc} |
602 ;; | \tau and \mu | $\tau$ and $\mu$ | \tau and \mu |
603 ;; |-----------------------+-----------------------+-----------------------|
604 ;; | \_ \^ | \_ \^ | \_ \^ |
605 ;; | \(a=\mu\mbox{m}\) | \(a=\mu\mbox{m}\) | \(a=\mu\mbox{m}\) |
606 ;; | \[\beta^2-a=0\] | \[\beta^2-a=0\] | \[\beta^2-a=0\] |
607 ;; | $x=22\tau$ | $x=22\tau$ | $x=22\tau$ |
608 ;; | $$\alpha=\sqrt{a^3}$$ | $$\alpha=\sqrt{a^3}$$ | $$\alpha=\sqrt{a^3}$$ |
610 (defun org-export-latex-special-chars (sub-superscript)
611 "Export special characters to LaTeX.
612 If SUB-SUPERSCRIPT is non-nil, convert \\ and ^.
613 See the `org-export-latex.el' code for a complete conversion table."
614 (goto-char (point-min))
616 (goto-char (point-min))
617 (while (re-search-forward c nil t
)
618 ;; Put the point where to check for org-protected
619 (unless (get-text-property (match-beginning 2) 'org-protected
)
620 (cond ((member (match-string 2) '("\\$" "$"))
621 (if (equal (match-string 2) "\\$")
622 (replace-match (concat (match-string 1) "$"
623 (match-string 3)) t t
)
624 (replace-match (concat (match-string 1) "\\$"
625 (match-string 3)) t t
)))
626 ((member (match-string 2) '("&" "#" "%"))
627 (if (equal (match-string 1) "\\")
628 (replace-match (match-string 2) t t
)
629 (replace-match (concat (match-string 1) "\\"
630 (match-string 2)) t t
)))
631 ((equal (match-string 2) "~")
632 (cond ((equal (match-string 1) "\\") nil
)
633 ((eq 'org-link
(get-text-property 0 'face
(match-string 2)))
634 (replace-match (concat (match-string 1) "\\~") t t
))
637 (concat (match-string 1) "\\~{}")) t t
))))
638 ((member (match-string 2) '("{" "}"))
639 (unless (save-match-data (org-inside-LaTeX-fragment-p))
640 (if (equal (match-string 1) "\\")
641 (replace-match (match-string 2) t t
)
642 (replace-match (concat (match-string 1) "\\"
643 (match-string 2)) t t
)))))
644 (unless (save-match-data (org-inside-LaTeX-fragment-p))
645 (cond ((equal (match-string 2) "\\")
646 (replace-match (or (save-match-data
647 (org-export-latex-treat-backslash-char
649 (match-string 3))) "") t t
))
650 ((member (match-string 2) '("_" "^"))
651 (replace-match (or (save-match-data
652 (org-export-latex-treat-sub-super-char
656 (match-string 3))) "") t t
)))))))
657 '("^\\([^\n$]*?\\|^\\)\\(\\\\?\\$\\)\\([^\n$]*\\)$"
658 "\\([a-za-z0-9]+\\|[ \t\n]\\|\\\\\\)\\(_\\|\\^\\)\\([a-za-z0-9]+\\|[ \t\n]\\|[:punct:]\\|{[a-za-z0-9]+}\\|([a-za-z0-9]+)\\)"
659 "\\(.\\|^\\)\\(\\\\\\)\\([ \t\n]\\|[a-za-z&#%{}]+\\)"
665 "\\(.\\|^\\)\\(~\\)")))
667 (defun org-export-latex-treat-sub-super-char
668 (subsup string-before char string-after
)
669 "Convert the \"_\" and \"^\" characters to LaTeX.
670 SUBSUP corresponds to the ^: option in the #+OPTIONS line.
671 Convert CHAR depending on STRING-BEFORE and STRING-AFTER."
672 (cond ((equal string-before
"\\")
673 (concat string-before char string-after
))
674 ;; this is part of a math formula
675 ((and (string-match "\\S-+" string-before
)
676 (string-match "\\S-+" string-after
))
677 (cond ((eq 'org-link
(get-text-property 0 'face char
))
678 (concat string-before
"\\" char string-after
))
679 ((save-match-data (org-inside-LaTeX-fragment-p))
681 (cond ((eq 1 (length string-after
))
682 (concat string-before char string-after
))
683 ((string-match "[({]?\\([^)}]+\\)[)}]?" string-after
)
684 (format "%s%s{%s}" string-before char
685 (match-string 1 string-after
))))))
687 (> (length string-after
) 1)
688 (string-match "[({]?\\([^)}]+\\)[)}]?" string-after
))
689 (format "$%s%s{%s}$" string-before char
690 (match-string 1 string-after
)))
691 (subsup (concat "$" string-before char string-after
"$"))
692 (t (concat string-before
"\\" char string-after
))))
693 (t (concat string-before
"\\" char string-after
))))
695 (defun org-export-latex-treat-backslash-char (string-before string-after
)
696 "Convert the \"$\" special character to LaTeX.
697 The conversion is made depending of STRING-BEFORE and STRING-AFTER."
698 (cond ((member (list string-after
) org-html-entities
)
699 ;; backslash is part of a special entity (like "\alpha")
700 (concat string-before
"$\\"
701 (or (cdar (member (list string-after
) org-html-entities
))
703 ((and (not (string-match "^[ \n\t]" string-after
))
704 (not (string-match "[ \t]\\'" string-before
)))
705 ;; backslash is inside a word
706 (concat string-before
"$\\backslash$" string-after
))
707 ((not (or (equal string-after
"")
708 (string-match "^[ \t\n]" string-after
)))
709 ;; backslash might escape a character (like \#) or a user TeX
710 ;; macro (like \setcounter)
711 (concat string-before
"\\" string-after
))
712 ((and (string-match "^[ \t\n]" string-after
)
713 (string-match "[ \t\n]\\'" string-before
))
714 ;; backslash is alone, convert it to $\backslash$
715 (concat string-before
"$\\backslash$" string-after
))
716 (t (concat string-before
"$\\backslash$" string-after
))))
718 (defun org-export-latex-fixed-width (opt)
719 "When OPT is non-nil convert fixed-width sections to LaTeX."
720 (goto-char (point-min))
721 (while (re-search-forward "^[ \t]*:" nil t
)
723 (progn (goto-char (match-beginning 0))
724 (insert "\\begin{verbatim}\n")
725 (while (looking-at "^\\([ \t]*\\):\\(.*\\)$")
726 (replace-match (concat (match-string 1)
727 (match-string 2)) t t
)
729 (insert "\\end{verbatim}\n\n"))
730 (progn (goto-char (match-beginning 0))
731 (while (looking-at "^\\([ \t]*\\):\\(.*\\)$")
732 (replace-match (concat "%" (match-string 1)
733 (match-string 2)) t t
)
736 ;; FIXME Use org-export-highlight-first-table-line ?
737 (defun org-export-latex-tables (opt)
738 "When OPT is non-nil convert tables to LaTeX."
739 (goto-char (point-min))
740 (while (re-search-forward "^\\([ \t]*\\)|" nil t
)
741 ;; Re-align the table to update org-table-last-alignment
742 (save-excursion (save-match-data (org-table-align)))
744 (beg (match-beginning 0))
747 (concat "^" (regexp-quote (match-string 1))
748 "[^|]\\|\\'") nil t
) (match-beginning 0))))
750 (while (not (eq end
(point)))
751 (if (looking-at "[ \t]*|\\([^-|].+\\)|[ \t]*$")
752 (push (split-string (org-trim (match-string 1)) "|") tbl-list
)
753 (push 'hline tbl-list
))
755 ;; comment region out instead of deleting it ?
756 (apply 'delete-region
(list beg end
))
757 (when opt
(insert (orgtbl-to-latex (nreverse tbl-list
)
760 (defun org-export-latex-keywords ()
761 "Convert special keywords to LaTeX.
762 Regexps are those from `org-latex-special-string-regexps'."
763 (let ((rg org-latex-special-string-regexps
) r
)
764 (while (setq r
(pop rg
))
765 (goto-char (point-min))
766 (while (re-search-forward (eval r
) nil t
)
767 (replace-match (format "\\\\texttt{%s}" (match-string 0)) t
)))))
769 ;; FIXME - we need better implementation for nested lists
770 (defun org-export-latex-list (srch0 srch1 srch2 rpl0 rpl1
)
771 "Convert lists to LaTeX."
772 (goto-char (point-min))
773 (while (re-search-forward srch0 nil t
)
774 (let* ((beg (match-beginning 0))
775 (prefix (regexp-quote (match-string 1)))
776 (end-string (when (re-search-forward srch1 nil t
)
778 (goto-char beg
) (insert rpl0
)
779 (while (re-search-forward
780 (concat "^" prefix srch2
)
786 (regexp-quote end-string
) nil t
)))) t
)
790 (format "\\texttt{%s}" (match-string 1))))
792 (goto-char (if end-string
793 (progn (re-search-forward
794 (regexp-quote end-string
) nil t
)
797 (skip-chars-backward "\n") (forward-line 2)
800 (defun org-export-latex-itemize ()
801 "Convert item list to LaTeX."
802 (org-export-latex-list
809 (defun org-export-latex-enumerate ()
810 "Convert numeric list to LaTeX."
811 (org-export-latex-list
812 "^\\([ \t]*\\)[0-9]+[\.)] \\(\\[.+\\]\\)? ?"
814 "[0-9]+[\.)] ?\\(\\[.+\\]\\)?"
815 "\\begin{enumerate}\n"
816 "\\end{enumerate}\n"))
818 (defun org-export-latex-fontify ()
819 "Convert fontification to LaTeX."
820 (goto-char (point-min))
821 (while (re-search-forward org-emph-re nil t
)
822 ;; The match goes one char after the *string*
823 (unless (get-text-property (1- (point)) 'org-protected
)
825 (concat (match-string 1)
827 (org-export-latex-protect-char-in-string
829 (cadr (assoc (match-string 3)
830 org-export-latex-emphasis-alist
)))
832 (match-string 5)) t t
)
835 (defun org-export-latex-protect-char-in-string (char-list string
)
836 "Add org-protected text-property to char from CHAR-LIST in STRING."
840 (goto-char (point-min))
841 (while (re-search-forward (regexp-opt char-list
) nil t
)
842 (add-text-properties (match-beginning 0)
843 (match-end 0) '(org-protected t
)))
846 (defun org-export-latex-links ()
847 ;; Make sure to use the LaTeX hyperref and graphicx package
848 ;; or send some warnings.
849 "Convert links to LaTeX."
850 (goto-char (point-min))
851 (while (re-search-forward org-bracket-link-analytic-regexp nil t
)
853 (goto-char (match-beginning 0))
854 (let* ((re-radio org-latex-all-targets-regexp
)
855 (remove (list (match-beginning 0) (match-end 0)))
856 (type (match-string 2))
857 (raw-path (match-string 3))
858 (full-raw-path (concat (match-string 1) raw-path
))
859 (desc (match-string 5))
861 ;; define the path of the link
863 ((member type
'("http" "https" "ftp"))
864 (concat type
":" raw-path
))
865 ((and re-radio
(string-match re-radio raw-path
))
867 ((equal type
"mailto")
868 (concat type
":" raw-path
))
870 (if (and (or (org-file-image-p (expand-file-name raw-path
))
871 (string-match "\\.eps$" raw-path
))
872 (equal desc full-raw-path
))
874 (progn (when (string-match "\\(.+\\)::.+" raw-path
)
875 (setq raw-path
(match-string 1 raw-path
)))
876 (if (file-exists-p raw-path
)
877 (concat type
"://" (expand-file-name raw-path
))
878 (concat type
"://" (org-export-directory
879 :LaTeX org-latex-options-plist
)
881 ;; process with link inserting
882 (apply 'delete-region remove
)
883 (cond ((and imgp
(plist-get org-latex-options-plist
:inline-images
))
884 (insert (format "\\includegraphics[%s]{%s}"
885 ;; image option should be set be a comment line
886 org-export-latex-image-default-option
887 (expand-file-name raw-path
))))
888 ;; FIXME: what about caption? image properties?
889 (radiop (insert (format "\\hyperref[%s]{%s}" raw-path desc
)))
890 (path (insert (format "\\href{%s}{%s}" path desc
)))
891 (t (insert "\\texttt{" desc
"}")))))))
894 (defun org-latex-cleaned-string-for-export (string &rest parameters
)
895 "Cleanup a buffer STRING so that links can be created safely."
897 (let* ((re-radio (and org-target-link-regexp
898 (concat "\\([^<]\\)\\(" org-target-link-regexp
"\\)")))
899 (re-plain-link (concat "\\([^[<]\\)" org-plain-link-re
))
900 (re-angle-link (concat "\\([^[]\\)" org-angle-link-re
))
901 (re-archive (concat ":" org-archive-tag
":"))
902 (re-quote (concat "^\\*+[ \t]+" org-quote-string
"\\>"))
903 (htmlp (plist-get parameters
:for-html
))
904 (latexp (plist-get parameters
:for-LaTeX
))
905 (commentsp (plist-get parameters
:comments
))
906 (inhibit-read-only t
)
907 (outline-regexp "\\*+ ")
911 (set-buffer (get-buffer-create " org-mode-tmp"))
914 ;; Remove license-to-kill stuff
915 (while (setq p
(text-property-any (point-min) (point-max)
916 :org-license-to-kill t
))
917 (delete-region p
(next-single-property-change p
:org-license-to-kill
)))
919 (let ((org-inhibit-startup t
)) (org-mode))
920 (untabify (point-min) (point-max))
922 ;; Get the correct stuff before the first headline
923 (when (plist-get parameters
:skip-before-1st-heading
)
924 (goto-char (point-min))
925 (when (re-search-forward "^\\*+[ \t]" nil t
)
926 (delete-region (point-min) (match-beginning 0))
927 (goto-char (point-min))
929 (when (plist-get parameters
:add-text
)
930 (goto-char (point-min))
931 (insert (plist-get parameters
:add-text
) "\n"))
933 ;; Get rid of archived trees
934 (when (not (eq org-export-with-archived-trees t
))
935 (goto-char (point-min))
936 (while (re-search-forward re-archive nil t
)
937 (if (not (org-on-heading-p t
))
938 (org-end-of-subtree t
)
939 (beginning-of-line 1)
940 (setq a
(if org-export-with-archived-trees
941 (1+ (point-at-eol)) (point))
942 b
(org-end-of-subtree t
))
943 (if (> b a
) (delete-region a b
)))))
945 ;; Get rid of property drawers
946 (unless org-export-with-property-drawer
947 (goto-char (point-min))
948 (while (re-search-forward "^[ \t]*:PROPERTIES:[ \t]*\n\\([^@]*?\n\\)?[ \t]*:END:[ \t]*\n" nil t
)
951 ;; Find targets in comments and move them out of comments,
952 ;; but mark them as targets that should be invisible
953 (goto-char (point-min))
954 (while (re-search-forward "^#.*?\\(<<<?[^>\r\n]+>>>?\\).*" nil t
)
955 (replace-match "\\1(INVISIBLE)"))
957 ;; Specific LaTeX cleaning
959 (require 'org-export-latex nil t
)
960 (org-export-latex-cleaned-string))
962 ;; Protect stuff from HTML processing
963 (goto-char (point-min))
964 (let ((formatters `((,htmlp
"HTML" "BEGIN_HTML" "END_HTML"))) fmt
)
965 (while (re-search-forward "^[ \t]*:.*\\(\n[ \t]*:.*\\)*" nil t
)
966 (add-text-properties (match-beginning 0) (match-end 0)
969 (setq fmt
(pop formatters
))
971 (goto-char (point-min))
972 (while (re-search-forward (concat "^#\\+" (cadr fmt
)
973 ":[ \t]*\\(.*\\)") nil t
)
974 (replace-match "\\1" t
)
976 (point-at-bol) (min (1+ (point-at-eol)) (point-max))
977 '(org-protected t
))))
978 (goto-char (point-min))
979 (while (re-search-forward
981 (caddr fmt
) "\\>.*\\(\\(\n.*\\)*?\n\\)#\\+"
982 (cadddr fmt
) "\\>.*\n?") nil t
)
984 (add-text-properties (match-beginning 1) (1+ (match-end 1))
986 (delete-region (match-beginning 0) (match-end 0))))
987 (goto-char (point-min))
988 (while (re-search-forward re-quote nil t
)
989 (goto-char (match-beginning 0))
991 (add-text-properties (point) (org-end-of-subtree t
)
992 '(org-protected t
)))))
994 ;; Remove or replace comments
995 ;; If :comments is set, use this char for commenting out comments and
996 ;; protect them. otherwise delete them
997 (goto-char (point-min))
998 (while (re-search-forward "^#\\(.*\n?\\)" nil t
)
1000 (progn (add-text-properties
1001 (match-beginning 0) (match-end 0) '(org-protected t
))
1002 (replace-match (format commentsp
(match-string 1)) t t
))
1003 (replace-match "")))
1005 ;; Find matches for radio targets and turn them into internal links
1006 (goto-char (point-min))
1008 (while (re-search-forward re-radio nil t
)
1010 (replace-match "\\1[[\\2]]"))))
1012 ;; Find all links that contain a newline and put them into a single line
1013 (goto-char (point-min))
1014 (while (re-search-forward "\\(\\(\\[\\|\\]\\)\\[[^]]*?\\)[ \t]*\n[ \t]*\\([^]]*\\]\\(\\[\\|\\]\\)\\)" nil t
)
1016 (replace-match "\\1 \\3")
1017 (goto-char (match-beginning 0))))
1019 ;; Convert LaTeX fragments to images
1020 (when (plist-get parameters
:LaTeX-fragments
)
1022 (concat "ltxpng/" (file-name-sans-extension
1023 (file-name-nondirectory
1024 org-current-export-file
)))
1025 org-current-export-dir nil
"Creating LaTeX image %s"))
1026 (message "Exporting...")
1028 ;; Normalize links: Convert angle and plain links into bracket links
1029 ;; Expand link abbreviations
1030 (goto-char (point-min))
1031 (while (re-search-forward re-plain-link nil t
)
1032 (goto-char (1- (match-end 0)))
1034 (let* ((s (concat (match-string 1) "[[" (match-string 2)
1035 ":" (match-string 3) "]]")))
1036 ;; added 'org-protected property to links
1037 (put-text-property 0 (length s
) 'face
'org-link s
)
1038 (replace-match s t t
))))
1039 (goto-char (point-min))
1040 (while (re-search-forward re-angle-link nil t
)
1041 (goto-char (1- (match-end 0)))
1043 (let* ((s (concat (match-string 1) "[[" (match-string 2)
1044 ":" (match-string 3) "]]")))
1045 (put-text-property 0 (length s
) 'face
'org-link s
)
1046 (replace-match s t t
))))
1047 (goto-char (point-min))
1048 (while (re-search-forward org-bracket-link-regexp nil t
)
1050 (let* ((s (concat "[[" (setq xx
(save-match-data
1051 (org-link-expand-abbrev (match-string 1))))
1055 (concat "[" xx
"]"))
1057 (put-text-property 0 (length s
) 'face
'org-link s
)
1058 (replace-match s t t
))))
1060 ;; Find multiline emphasis and put them into single line
1061 (when (plist-get parameters
:emph-multiline
)
1062 (goto-char (point-min))
1063 (while (re-search-forward org-emph-re nil t
)
1064 (if (not (= (char-after (match-beginning 3))
1065 (char-after (match-beginning 4))))
1067 (subst-char-in-region (match-beginning 0) (match-end 0)
1069 (goto-char (1- (match-end 0))))
1070 (goto-char (1+ (match-beginning 0))))))
1072 (setq rtn
(buffer-string)))
1073 (kill-buffer " org-mode-tmp")
1076 (defsubst org-latex-protect
(string)
1077 (add-text-properties 0 (length string
) '(org-protected t
) string
) string
)
1079 (defun org-export-latex-cleaned-string ()
1080 "Clean stuff in the LaTeX export."
1082 ;; Preserve line breaks
1083 (goto-char (point-min))
1084 (while (re-search-forward "\\\\\\\\" nil t
)
1085 (add-text-properties (match-beginning 0) (match-end 0)
1086 '(org-protected t
)))
1088 ;; Convert LaTeX to @LaTeX{}
1089 (goto-char (point-min))
1090 (let ((case-fold-search nil
) rpl
)
1091 (while (re-search-forward "\\([^+_]\\)LaTeX" nil t
)
1092 (replace-match (org-latex-protect
1093 (concat (match-string 1) "\\LaTeX{}")) t t
)))
1095 ;; Convert horizontal rules
1096 (goto-char (point-min))
1097 (while (re-search-forward "^----+.$" nil t
)
1098 (replace-match (org-latex-protect "\\hrule") t t
))
1100 ;; Remove COMMENT subtrees
1101 ;; What about QUOTE subtrees?
1102 (goto-char (point-min))
1103 (while (re-search-forward
1104 (concat "^\\*+ \\(" org-comment-string
"\\)")
1109 ;; Protect LaTeX \commands{...}
1110 (goto-char (point-min))
1111 (while (re-search-forward "\\\\[a-z]+\\(?:\\[.*\\]\\)?\\(?:{.*}\\)?" nil t
)
1112 (add-text-properties (match-beginning 0) (match-end 0)
1113 '(org-protected t
)))
1115 ;; Replace radio links
1116 (goto-char (point-min))
1117 (let ((search (concat "<<<?" org-latex-all-targets-regexp
">?>>")))
1118 (while (re-search-forward search nil t
)
1120 (org-latex-protect (format "\\label{%s}" (match-string 1))) t t
)))
1122 ;; Delete @<...> constructs
1123 (goto-char (point-min))
1124 ;; Thanks to Daniel Clemente for this regexp
1125 (while (re-search-forward "@<\\(?:[^\"\n]\\|\".*\"\\)*?>" nil t
)
1128 ;; Add #+BEGIN_LaTeX before any \begin{...}
1129 (goto-char (point-min))
1130 (while (re-search-forward "^ *\\\\begin{" nil t
)
1131 (replace-match "#+BEGIN_LaTeX:\n\\&" t
))
1133 ;; Add #+END_LaTeX after any \end{...}
1134 (goto-char (point-min))
1135 (while (re-search-forward "^ *\\\\end{.+}.*$" nil t
)
1136 (replace-match "\\&\n#+END_LaTeX" t
))
1138 ;; When converting to LaTeX, replace footnotes
1139 ;; FIXME: don't protect footnotes from conversion
1140 (when (plist-get org-latex-options-plist
:footnotes
)
1141 (goto-char (point-min))
1142 (while (re-search-forward "\\[[0-9]+\\]" nil t
)
1143 (when (save-match-data
1144 (save-excursion (beginning-of-line)
1145 (looking-at "[^:|]")))
1146 (let ((foot-beg (match-beginning 0))
1147 (foot-end (match-end 0))
1148 (foot-prefix (match-string 0))
1149 footnote footnote-rpl
)
1150 (when (and (re-search-forward (regexp-quote foot-prefix
) nil t
))
1152 (let ((end (save-excursion
1153 (if (re-search-forward "^$\\|\\[[0-9]+\\]" nil t
)
1154 (match-beginning 0) (point-max)))))
1155 (setq footnote
(concat
1156 (org-trim (buffer-substring (point) end
))
1157 ;; FIXME stupid workaround for cases where
1158 ;; `org-bracket-link-analytic-regexp' matches
1159 ;; }. as part of the link.
1161 (delete-region (point) end
)))
1162 (goto-char foot-beg
)
1163 (delete-region foot-beg foot-end
)
1164 (setq footnote-rpl
(format "\\footnote{%s}" footnote
))
1165 (add-text-properties 0 10 '(org-protected t
) footnote-rpl
)
1166 (add-text-properties (1- (length footnote-rpl
))
1167 (length footnote-rpl
)
1168 '(org-protected t
) footnote-rpl
)
1169 (insert footnote-rpl
))))
1171 ;; Replace footnote section tag for LaTeX
1172 (goto-char (point-min))
1173 (while (re-search-forward
1174 (concat "^" footnote-section-tag-regexp
) nil t
)
1175 (replace-match "")))
1177 ;; Protect stuff from LaTeX processing.
1178 ;; We will get rid on this once org.el integrate org-export-latex.el
1179 (goto-char (point-min))
1180 (let ((formatters `((,latexp
"LaTeX" "BEGIN_LaTeX" "END_LaTeX"))) fmt
)
1181 (while (re-search-forward "^[ \t]*:.*\\(\n[ \t]*:.*\\)*" nil t
)
1182 (add-text-properties (match-beginning 0) (match-end 0)
1183 '(org-protected t
)))
1185 (setq fmt
(pop formatters
))
1187 (goto-char (point-min))
1188 (while (re-search-forward (concat "^#\\+" (cadr fmt
)
1189 ;; ":[ \t]*\\(.*\\)") nil t)
1190 ;; FIXME: authorize spaces after #+LaTeX:
1191 ;; to get list correctly exported
1193 (replace-match "\\1" t
)
1194 (add-text-properties
1195 (point-at-bol) (min (1+ (point-at-eol)) (point-max))
1196 '(org-protected t
))))
1197 (goto-char (point-min))
1198 (while (re-search-forward
1200 (caddr fmt
) "\\>.*\\(\\(\n.*\\)*?\n\\)#\\+"
1201 (cadddr fmt
) "\\>.*\n?") nil t
)
1203 (add-text-properties (match-beginning 1) (1+ (match-end 1))
1205 (delete-region (match-beginning 0) (match-end 0))))
1206 (goto-char (point-min))
1207 (while (re-search-forward re-quote nil t
)
1208 (goto-char (match-beginning 0))
1210 (add-text-properties (point) (org-end-of-subtree t
)
1211 '(org-protected t
))))))
1213 (provide 'org-export-latex
)
1215 ;;; org-export-latex.el ends here