Release 5.06d
[org-mode/org-tableheadings.git] / org-export-latex.el
blob04e167cda2e9b003baccad80737a63854230a31f
1 ;;; org-export-latex.el --- LaTeX exporter for Org-mode
2 ;; Copyright (C) 2007 Free Software Foundation, Inc.
3 ;;
4 ;; Author: Bastien Guerry <bzg AT altern DOT org>
5 ;; Maintainer: Bastien Guerry <bzg AT altern DOT org>
6 ;; Version: $Id: org-export-latex.el,v 0.26b 2007/08/21 14:46:58 guerry Exp guerry $
7 ;; Keywords: org organizer latex export convert
8 ;; X-URL: <http://www.cognition.ens.fr/~guerry/u/org-export-latex.el>
9 ;;
10 ;; This file is part of GNU Emacs.
12 ;; This program is free software; you can redistribute it and/or modify
13 ;; it under the terms of the GNU General Public License as published by
14 ;; the Free Software Foundation; either version 2, or (at your option)
15 ;; any later version.
17 ;; This program is distributed in the hope that it will be useful,
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 ;; GNU General Public License for more details.
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with this program; if not, write to the Free Software
24 ;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 ;;; Commentary:
28 ;; This library is a LaTeX exporter for org-mode.
29 ;;
30 ;; Put this file into your load-path and the following into your ~/.emacs:
31 ;; (require 'org-export-latex)
32 ;;
33 ;; The interactive functions are similar to those of the HTML exporter:
34 ;;
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'
41 ;;; History:
42 ;;
43 ;; I started this piece of code in may 2007. Special thanks to Carsten
44 ;; Dominik for helping me on this.
45 ;;
47 ;;; Code:
49 (require 'org)
50 (require 'footnote)
52 (defvar org-latex-options-plist nil)
53 (defvar org-latex-todo-keywords-1 nil)
54 (defvar org-latex-all-targets-regexp nil)
55 (defvar org-latex-add-level 0)
56 (defvar org-latex-sectioning-depth 0)
58 (defvar org-latex-special-string-regexps
59 '(org-ts-regexp
60 org-scheduled-string
61 org-deadline-string
62 org-clock-string)
63 "A list of regexps to convert as special keywords.")
65 (defcustom org-export-latex-sectioning-alist
66 '((1 "\\section{%s}" "\\section*{%s}")
67 (2 "\\subsection{%s}" "\\subsection*{%s}")
68 (3 "\\subsubsection{%s}" "\\subsubsection*{%s}")
69 (4 "\\paragraph{%s}" "\\paragraph*{%s}")
70 (5 "\\subparagraph{%s}" "\\subparagraph*{%s}"))
71 "Alist of LaTeX commands for inserting sections.
72 Here is the structure of each cell:
74 \(level unnumbered-section numbered-section\)
76 The %s formatter will be replaced by the title of the section."
77 :group 'org-export-latex
78 :type 'alist)
80 (defcustom org-export-latex-emphasis-alist
81 '(("*" "\\textbf{%s}")
82 ("/" "\\emph{%s}")
83 ("_" "\\underline{%s}")
84 ("+" "\\texttt{%s}")
85 ("=" "\\texttt{%s}"))
86 "Alist of LaTeX expressions to convert emphasis fontifiers."
87 :group 'org-export-latex
88 :type 'alist)
90 (defcustom org-export-latex-preamble
91 "\\documentclass[11pt,a4paper]{article}
92 \\usepackage[utf8]{inputenc}
93 \\usepackage[T1]{fontenc}
94 \\usepackage{hyperref}"
95 "Preamble to be inserted at the very beginning of the LaTeX export."
96 :group 'org-export-latex
97 :type 'string)
99 (defcustom org-export-latex-date-format nil
100 "Format string for \\date{...}."
101 :group 'org-export-latex
102 :type 'string)
104 (defcustom org-export-latex-packages-alist nil
105 "Alist of packages to be inserted in the preamble.
106 Each cell is of the forma \( option . package \).
108 For example:
110 \(setq org-export-latex-packages-alist
111 '((\"french\" \"babel\"))"
112 :group 'org-export-latex
113 :type 'alist)
115 (defcustom org-export-latex-low-levels 'description
116 "Choice for converting sections that are below the current
117 admitted level of sectioning. This can be either nil (ignore the
118 sections), 'description (convert them as description lists) or a
119 string to be used instead of \\section{%s} (a %s for inserted the
120 headline is mandatory)."
121 :group 'org-export-latex
122 :type '(choice (const :tag "Ignore" nil)
123 (symbol :tag "Convert as descriptive list" description)
124 (string :tag "Use a section string" :value "\\subparagraph{%s}")))
126 (defcustom org-export-latex-remove-from-headines
127 '(:todo t :priority t :tags t)
128 "A plist of keywords to remove from headlines.
129 Non-nil means remove this keyword type from the headline.
131 Don't remove the keys, just change their values."
132 :type 'plist
133 :group 'org-export-latex)
135 (defcustom org-export-latex-quotation-marks-convention "en"
136 "Convention for conversion of the quotation marks.
137 This value is overriden by any infile language setup."
138 :group 'org-export-latex
139 :type '(choice (string :tag "english" "en")
140 (string :tag "french" "fr")))
142 (defcustom org-export-latex-image-default-option "width=10em"
143 "Default option for images."
144 :group 'org-export-latex
145 :type '(string))
147 (defcustom org-export-latex-coding-system nil
148 "Coding system for the exported LaTex file."
149 :group 'org-export-latex
150 :type 'coding-system)
152 ;; FIXME Do we want this one?
153 ;; (defun org-export-as-latex-and-open (arg) ...)
155 ;;;###autoload
156 (defun org-export-as-latex-batch ()
157 "Call `org-export-as-latex', may be used in batch processing as
158 emacs --batch
159 --load=$HOME/lib/emacs/org.el
160 --eval \"(setq org-export-headline-levels 2)\"
161 --visit=MyFile --funcall org-export-as-latex-batch"
162 (org-export-as-latex org-export-headline-levels 'hidden))
164 ;;;###autoload
165 (defun org-export-as-latex-to-buffer (arg)
166 "Call `org-exort-as-latex` with output to a temporary buffer.
167 No file is created. The prefix ARG is passed through to `org-export-as-latex'."
168 (interactive "P")
169 (org-export-as-latex arg nil nil "*Org LaTeX Export*")
170 (switch-to-buffer-other-window "*Org LaTeX Export*"))
172 ;;;###autoload
173 (defun org-replace-region-by-latex (beg end)
174 "Replace the region from BEG to END with its LaTeX export.
175 It assumes the region has `org-mode' syntax, and then convert it to
176 LaTeX. This can be used in any buffer. For example, you could
177 write an itemized list in `org-mode' syntax in an LaTeX buffer and
178 then use this command to convert it."
179 (interactive "r")
180 (let (reg latex buf)
181 (save-window-excursion
182 (if (org-mode-p)
183 (setq latex (org-export-region-as-latex
184 beg end t 'string))
185 (setq reg (buffer-substring beg end)
186 buf (get-buffer-create "*Org tmp*"))
187 (save-excursion
188 (set-buffer buf)
189 (erase-buffer)
190 (insert reg)
191 (org-mode)
192 (setq latex (org-export-region-as-latex
193 (point-min) (point-max) t 'string)))
194 (kill-buffer buf)))
195 (delete-region beg end)
196 (insert latex)))
198 ;;;###autoload
199 (defun org-export-region-as-latex (beg end &optional body-only buffer)
200 "Convert region from BEG to END in `org-mode' buffer to LaTeX.
201 If prefix arg BODY-ONLY is set, omit file header, footer, and table of
202 contents, and only produce the region of converted text, useful for
203 cut-and-paste operations.
204 If BUFFER is a buffer or a string, use/create that buffer as a target
205 of the converted LaTeX. If BUFFER is the symbol `string', return the
206 produced LaTeX as a string and leave not buffer behind. For example,
207 a Lisp program could call this function in the following way:
209 (setq latex (org-export-region-as-latex beg end t 'string))
211 When called interactively, the output buffer is selected, and shown
212 in a window. A non-interactive call will only retunr the buffer."
213 (interactive "r\nP")
214 (when (interactive-p)
215 (setq buffer "*Org LaTeX Export*"))
216 (let ((transient-mark-mode t) (zmacs-regions t)
217 rtn)
218 (goto-char end)
219 (set-mark (point)) ;; to activate the region
220 (goto-char beg)
221 (setq rtn (org-export-as-latex
222 nil nil nil
223 buffer body-only))
224 (if (fboundp 'deactivate-mark) (deactivate-mark))
225 (if (and (interactive-p) (bufferp rtn))
226 (switch-to-buffer-other-window rtn)
227 rtn)))
229 ;;;###autoload
230 (defun org-export-as-latex (arg &optional hidden ext-plist
231 to-buffer body-only)
232 "Export current buffer to a LaTeX file."
233 (interactive "P")
234 ;; Make sure we have a file name when we need it.
235 (when (and (not (or to-buffer body-only))
236 (not buffer-file-name))
237 (if (buffer-base-buffer)
238 (org-set-local 'buffer-file-name
239 (with-current-buffer (buffer-base-buffer)
240 buffer-file-name))
241 (error "Need a file name to be able to export")))
243 (message "Exporting to LaTeX...")
244 (org-update-radio-target-regexp)
245 (org-export-latex-set-initial-vars ext-plist)
246 (let* ((opt-plist org-latex-options-plist)
247 (filename (concat (file-name-as-directory
248 (org-export-directory :LaTeX ext-plist))
249 (file-name-sans-extension
250 (file-name-nondirectory ;sans-extension
251 buffer-file-name)) ".tex"))
252 (filename (if (equal (file-truename filename)
253 (file-truename buffer-file-name))
254 (concat filename ".tex")
255 filename))
256 (buffer (if to-buffer
257 (cond
258 ((eq to-buffer 'string) (get-buffer-create
259 "*Org LaTeX Export*"))
260 (t (get-buffer-create to-buffer)))
261 (find-file-noselect filename)))
262 (region-p (org-region-active-p))
263 (odd org-odd-levels-only)
264 (preamble (org-export-latex-make-preamble opt-plist))
265 (skip (plist-get opt-plist :skip-before-1st-heading))
266 (text (plist-get opt-plist :text))
267 (first-lines (if skip "" (org-export-latex-first-lines)))
268 (coding-system (and (boundp 'buffer-file-coding-system)
269 buffer-file-coding-system))
270 (coding-system-for-write (or org-export-latex-coding-system
271 coding-system))
272 (save-buffer-coding-system (or org-export-latex-coding-system
273 coding-system))
274 (region (buffer-substring
275 (if region-p (region-beginning) (point-min))
276 (if region-p (region-end) (point-max))))
277 (string-for-export
278 ;; FIXME Use org-cleaned-string-for-export instead, only when
279 ;; everyone uses Org >5.04
280 (org-latex-cleaned-string-for-export
281 region :for-html nil
282 :comments nil
283 :for-LaTeX t
284 :skip-before-1st-heading nil
285 :LaTeX-fragments nil)))
286 (set-buffer buffer)
287 (erase-buffer)
288 (unless body-only (insert preamble))
289 (when text (insert (org-export-latex-content text) "\n\n"))
290 (unless skip (insert first-lines))
292 ;; handle the case where the region does not begin with a section
293 (when region-p
294 (insert (with-temp-buffer
295 (insert string-for-export)
296 (org-export-latex-first-lines))))
298 (org-export-latex-global
299 (with-temp-buffer
300 (insert string-for-export)
301 (goto-char (point-min))
302 (re-search-forward "^\\(\\*+\\) " nil t)
303 (let* ((asters (length (match-string 1)))
304 (level (if odd (- asters 2) (- asters 1))))
305 (setq org-latex-add-level
306 (if odd (1- (/ (1+ asters) 2)) (1- asters)))
307 (org-export-latex-parse-global level odd))))
309 (unless body-only (insert "\n\\end{document}"))
310 (or to-buffer (write-file filename))
311 (goto-char (point-min))
312 (message "Exporting to LaTeX...done")
313 (if (eq to-buffer 'string)
314 (prog1 (buffer-substring (point-min) (point-max))
315 (kill-buffer (current-buffer)))
316 (current-buffer))))
318 (defun org-export-latex-set-initial-vars (ext-plist)
319 "Store org local variables required for LaTeX export.
320 EXT-PLIST is an optional additional plist."
321 (setq org-latex-todo-keywords-1 org-todo-keywords-1
322 org-latex-all-targets-regexp
323 (org-make-target-link-regexp (org-all-targets))
324 org-latex-options-plist
325 (org-combine-plists (org-default-export-plist) ext-plist
326 (org-infile-export-plist))
327 org-latex-sectioning-depth
328 (let ((hl-levels (plist-get org-latex-options-plist :headline-levels))
329 (sec-depth (length org-export-latex-sectioning-alist)))
330 ;; Fall back on org-export-latex-sectioning-alist length if
331 ;; headline-levels goes beyond it
332 (if (> hl-levels sec-depth) sec-depth hl-levels))))
334 (defun org-export-latex-make-preamble (opt-plist)
335 "Make the LaTeX preamble and return it as a string.
336 Argument OPT-PLIST is the options plist for current buffer."
337 (let ((toc (plist-get opt-plist :table-of-contents)))
338 (format (concat org-export-latex-preamble
342 \\begin{document}
344 \\title{%s}
347 \\maketitle
351 (if org-export-latex-packages-alist
352 (mapconcat (lambda(p)
353 (if (equal "" (car p))
354 (format "\\usepackage{%s}" (cadr p))
355 (format "\\usepackage[%s]{%s}"
356 (car p) (cadr p))))
357 org-export-latex-packages-alist "\n") "")
358 (or (plist-get opt-plist :title)
359 (and (not
360 (plist-get opt-plist :skip-before-1st-heading))
361 (org-export-grab-title-from-buffer))
362 (and buffer-file-name
363 (file-name-sans-extension
364 (file-name-nondirectory buffer-file-name)))
365 "UNTITLED")
366 (if (plist-get opt-plist :author-info)
367 (format "\\author{%s}"
368 (or (plist-get opt-plist :author) user-full-name))
369 (format "%%\\author{%s}"
370 (or (plist-get opt-plist :author) user-full-name)))
371 (if (plist-get opt-plist :timestamps)
372 (format "\\date{%s}"
373 (format-time-string (or org-export-latex-date-format
374 (car org-time-stamp-formats))))
375 "%\\date{}")
376 (if (and (plist-get opt-plist :section-numbers) toc)
377 (format "\\setcounter{tocdepth}{%s}"
378 (plist-get opt-plist :headline-levels)) "")
379 (if (and (plist-get opt-plist :section-numbers) toc)
380 "\\tableofcontents" ""))))
382 (defun org-export-latex-first-lines (&optional comments)
383 "Export the first lines before first headline.
384 COMMENTS is either nil to replace them with the empty string or a
385 formatting string like %%%%s if we want to comment them out."
386 (save-excursion
387 (goto-char (point-min))
388 (let* ((end (if (re-search-forward "^\\*" nil t)
389 (goto-char (match-beginning 0))
390 (goto-char (point-max)))))
391 (org-export-latex-content
392 (org-latex-cleaned-string-for-export
393 (buffer-substring (point-min) end)
394 :for-html nil
395 :for-LaTeX t
396 :comments nil
397 :skip-before-1st-heading nil
398 :LaTeX-fragments nil)))))
400 (defun org-export-latex-parse-global (level odd)
401 "Parse the current buffer recursively, starting at LEVEL.
402 If ODD is non-nil, assume the buffer only contains odd sections.
403 Return A list reflecting the document structure."
404 (save-excursion
405 (goto-char (point-min))
406 (let* ((cnt 0) output
407 (depth org-latex-sectioning-depth))
408 (while (re-search-forward
409 (concat "^\\(\\(?:\\*\\)\\{"
410 (number-to-string (+ (if odd 2 1) level))
411 "\\}\\) \\(.*\\)$")
412 ;; make sure that there is no upper heading
413 (when (> level 0)
414 (save-excursion
415 (save-match-data
416 (re-search-forward
417 (concat "^\\(\\(?:\\*\\)\\{"
418 (number-to-string level)
419 "\\}\\) \\(.*\\)$") nil t)))) t)
420 (setq cnt (1+ cnt))
421 (let* ((pos (match-beginning 0))
422 (heading (match-string 2))
423 (nlevel (if odd (/ (+ 3 level) 2) (1+ level))))
424 (save-excursion
425 (narrow-to-region
426 (point)
427 (save-match-data
428 (if (re-search-forward
429 (concat "^\\(\\(?:\\*\\)\\{"
430 (number-to-string (+ (if odd 2 1) level))
431 "\\}\\) \\(.*\\)$") nil t)
432 (match-beginning 0)
433 (point-max))))
434 (goto-char (point-min))
435 (setq output
436 (append output
437 (list
438 (list
439 `(pos . ,pos)
440 `(level . ,nlevel)
441 `(occur . ,cnt)
442 `(heading . ,heading)
443 `(content . ,(org-export-latex-parse-content))
444 `(subcontent . ,(org-export-latex-parse-subcontent
445 level odd)))))))
446 (widen)))
447 (list output))))
449 (defun org-export-latex-parse-content ()
450 "Extract the content of a section."
451 (let ((beg (point))
452 (end (if (re-search-forward "^\\(\\*\\)+ .*$" nil t)
453 (progn (beginning-of-line) (point))
454 (point-max))))
455 (buffer-substring beg end)))
457 (defun org-export-latex-parse-subcontent (level odd)
458 "Extract the subcontent of a section at LEVEL.
459 If ODD Is non-nil, assume subcontent only contains odd sections."
460 (if (not (re-search-forward
461 (concat "^\\(\\(?:\\*\\)\\{"
462 (number-to-string (+ (if odd 4 2) level))
463 "\\}\\) \\(.*\\)$")
464 nil t))
465 nil ; subcontent is nil
466 (org-export-latex-parse-global (+ (if odd 2 1) level) odd)))
468 (defun org-export-latex-global (content)
469 "Export CONTENT to LaTeX.
470 CONTENT is an element of the list produced by
471 `org-export-latex-parse-global'."
472 (if (eq (car content) 'subcontent)
473 (mapc 'org-export-latex-sub (cdr content))
474 (org-export-latex-sub (car content))))
476 (defun org-export-latex-sub (subcontent)
477 "Export the list SUBCONTENT to LaTeX.
478 SUBCONTENT is an alist containing information about the headline
479 and its content."
480 (mapc (lambda(x) (org-export-latex-subcontent x)) subcontent))
482 (defun org-export-latex-subcontent (subcontent)
483 "Export each cell of SUBCONTENT to LaTeX."
484 (let ((heading (org-export-latex-fontify-headline
485 (cdr (assoc 'heading subcontent))))
486 (level (- (cdr (assoc 'level subcontent))
487 org-latex-add-level))
488 (occur (number-to-string (cdr (assoc 'occur subcontent))))
489 (content (cdr (assoc 'content subcontent)))
490 (subcontent (cadr (assoc 'subcontent subcontent)))
491 (num (plist-get org-latex-options-plist :section-numbers)))
492 (cond
493 ;; Normal conversion
494 ((<= level org-latex-sectioning-depth)
495 (let ((sec (assoc level org-export-latex-sectioning-alist)))
496 (insert (format (if num (cadr sec) (caddr sec)) heading) "\n"))
497 (insert (org-export-latex-content content))
498 (cond ((stringp subcontent) (insert subcontent))
499 ((listp subcontent) (org-export-latex-sub subcontent))))
500 ;; At a level under the hl option: we can drop this subsection
501 ((> level org-latex-sectioning-depth)
502 (cond ((eq org-export-latex-low-levels 'description)
503 (insert (format "\\begin{description}\n\n\\item[%s]\n\n" heading))
504 (insert (org-export-latex-content content))
505 (cond ((stringp subcontent) (insert subcontent))
506 ((listp subcontent) (org-export-latex-sub subcontent)))
507 (insert "\\end{description}\n"))
508 ((stringp org-export-latex-low-levels)
509 (insert (format org-export-latex-low-levels heading) "\n")
510 (insert (org-export-latex-content content))
511 (cond ((stringp subcontent) (insert subcontent))
512 ((listp subcontent) (org-export-latex-sub subcontent)))))))))
514 (defun org-export-latex-special-keywords-maybe (remove-list)
515 "Maybe remove keywords depending on rules in REMOVE-LIST."
516 (goto-char (point-min))
517 (let ((re-todo (mapconcat 'identity org-latex-todo-keywords-1 "\\|")))
518 ;; convert TODO keywords
519 (when (re-search-forward (concat "^\\(" re-todo "\\)") nil t)
520 (if (plist-get remove-list :todo)
521 (replace-match "")
522 (replace-match (format "\\texttt{%s}" (match-string 1)) t t)))
523 ;; convert priority string
524 (when (re-search-forward "\\[\\\\#.\\]" nil t)
525 (if (plist-get remove-list :priority)
526 (replace-match "")
527 (replace-match (format "\\texttt{%s}" (match-string 0)) t t)))
528 ;; convert tags
529 (when (re-search-forward "\\(:[a-zA-Z0-9]+\\)+:" nil t)
530 (if (plist-get remove-list :tags)
531 (replace-match "")
532 (replace-match (format "\\texttt{%s}" (match-string 0)) t t)))))
534 (defun org-export-latex-fontify-headline (headline)
535 "Fontify special words in a HEADLINE."
536 (with-temp-buffer
537 ;; FIXME: org-inside-LaTeX-fragment-p doesn't work when the $...$ is at
538 ;; the beginning of the buffer - inserting "\n" is safe here though.
539 (insert "\n" headline)
540 (goto-char (point-min))
541 (org-export-latex-special-chars
542 (plist-get org-latex-options-plist :sub-superscript))
543 (when (plist-get org-latex-options-plist :emphasize)
544 (org-export-latex-fontify))
545 (org-export-latex-special-keywords-maybe
546 org-export-latex-remove-from-headines)
547 (org-export-latex-links)
548 (org-trim (buffer-substring-no-properties (point-min) (point-max)))))
550 (defun org-export-latex-content (content)
551 "Convert CONTENT string to LaTeX."
552 (with-temp-buffer
553 (insert content)
554 (org-export-latex-quotation-marks)
555 (org-export-latex-special-chars
556 (plist-get org-latex-options-plist :sub-superscript))
557 (when (plist-get org-latex-options-plist :emphasize)
558 (org-export-latex-fontify))
559 (org-export-latex-links)
560 (org-export-latex-special-keywords)
561 (org-export-latex-itemize)
562 (org-export-latex-enumerate)
563 (org-export-latex-tables
564 (plist-get org-latex-options-plist :tables))
565 (org-export-latex-fixed-width
566 (plist-get org-latex-options-plist :fixed-width))
567 (org-export-fix-invisible-strings)
568 (buffer-substring (point-min) (point-max))))
570 (defun org-export-fix-invisible-strings ()
571 "Comment out (INVISIBLE) warnings."
572 (goto-char (point-min))
573 (while (re-search-forward "(INVISIBLE)" nil t)
574 (replace-match "%\\&")))
576 (defun org-export-latex-quotation-marks ()
577 "Export question marks depending on language conventions.
578 Local definition of the language overrides
579 `org-export-latex-quotation-marks-convention' which overrides
580 `org-export-default-language'."
581 (let* ((lang (or (plist-get org-latex-options-plist :language)
582 org-export-latex-quotation-marks-convention))
583 (quote-rpl (if (equal lang "fr")
584 '(("\\(\\s-\\)\"" "«~")
585 ("\\(\\S-\\)\"" "~»")
586 ("\\(\\s-\\)'" "`"))
587 '(("\\(\\s-\\)\"" "``")
588 ("\\(\\S-\\)\"" "''")
589 ("\\(\\s-\\)'" "`")))))
590 (mapc (lambda(l) (goto-char (point-min))
591 (while (re-search-forward (car l) nil t)
592 (let ((rpl (concat (match-string 1) (cadr l))))
593 (org-latex-protect rpl)
594 (org-if-unprotected
595 (replace-match rpl t t))))) quote-rpl)))
597 ;; | chars/string in Org | normal environment | math environment |
598 ;; |-----------------------+-----------------------+-----------------------|
599 ;; | & # % $ | \& \# \% \$ | \& \# \% \$ |
600 ;; | { } _ ^ \ | \ { \ } \_ \^ \\ | { } _ ^ \ |
601 ;; |-----------------------+-----------------------+-----------------------|
602 ;; | a_b and a^b | $a_b$ and $a^b$ | a_b and a^b |
603 ;; | a_abc and a_{abc} | $a_a$bc and $a_{abc}$ | a_abc and a_{abc} |
604 ;; | \tau and \mu | $\tau$ and $\mu$ | \tau and \mu |
605 ;; |-----------------------+-----------------------+-----------------------|
606 ;; | \_ \^ | \_ \^ | \_ \^ |
607 ;; | \(a=\mu\mbox{m}\) | \(a=\mu\mbox{m}\) | \(a=\mu\mbox{m}\) |
608 ;; | \[\beta^2-a=0\] | \[\beta^2-a=0\] | \[\beta^2-a=0\] |
609 ;; | $x=22\tau$ | $x=22\tau$ | $x=22\tau$ |
610 ;; | $$\alpha=\sqrt{a^3}$$ | $$\alpha=\sqrt{a^3}$$ | $$\alpha=\sqrt{a^3}$$ |
612 (defun org-export-latex-special-chars (sub-superscript)
613 "Export special characters to LaTeX.
614 If SUB-SUPERSCRIPT is non-nil, convert \\ and ^.
615 See the `org-export-latex.el' code for a complete conversion table."
616 (goto-char (point-min))
617 (mapc (lambda(c)
618 (goto-char (point-min))
619 (while (re-search-forward c nil t)
620 ;; Put the point where to check for org-protected
621 (unless (get-text-property (match-beginning 2) 'org-protected)
622 (cond ((member (match-string 2) '("\\$" "$"))
623 (if (equal (match-string 2) "\\$")
624 (replace-match (concat (match-string 1) "$"
625 (match-string 3)) t t)
626 (replace-match (concat (match-string 1) "\\$"
627 (match-string 3)) t t)))
628 ((member (match-string 2) '("&" "#" "%"))
629 (if (equal (match-string 1) "\\")
630 (replace-match (match-string 2) t t)
631 (replace-match (concat (match-string 1) "\\"
632 (match-string 2)) t t)))
633 ((equal (match-string 2) "~")
634 ;; FIXME protect ~ in links
635 ;; (unless (get-text-property 0 'org-protected (match-string 2))
636 ;; (unless (eq 'org-link (get-text-property 0 'face (match-string 2)))
637 (cond ((equal (match-string 1) "\\") nil)
638 ((eq 'org-link (get-text-property 0 'face (match-string 2)))
639 (replace-match (concat (match-string 1) "\\~") t t))
641 (replace-match
642 (org-latex-protect
643 (concat (match-string 1) "\\textasciitilde{}")) t t))))
644 ((member (match-string 2) '("{" "}"))
645 (unless (save-match-data (org-inside-LaTeX-fragment-p))
646 (if (equal (match-string 1) "\\")
647 (replace-match (match-string 2) t t)
648 (replace-match (concat (match-string 1) "\\"
649 (match-string 2)) t t)))))
650 (unless (save-match-data (org-inside-LaTeX-fragment-p))
651 (cond ((equal (match-string 2) "\\")
652 (replace-match (or (save-match-data
653 (org-export-latex-treat-backslash-char
654 (match-string 1)
655 (match-string 3))) "") t t))
656 ((member (match-string 2) '("_" "^"))
657 (replace-match (or (save-match-data
658 (org-export-latex-treat-sub-super-char
659 sub-superscript
660 (match-string 1)
661 (match-string 2)
662 (match-string 3))) "") t t)))))))
663 '("^\\([^\n$]*?\\|^\\)\\(\\\\?\\$\\)\\([^\n$]*\\)$"
664 "\\([a-za-z0-9]+\\|[ \t\n]\\|\\\\\\)\\(_\\|\\^\\)\\([a-za-z0-9]+\\|[ \t\n]\\|[:punct:]\\|{[a-za-z0-9]+}\\|([a-za-z0-9]+)\\)"
665 "\\(.\\|^\\)\\(\\\\\\)\\([ \t\n]\\|[a-za-z&#%{}]+\\)"
666 "\\(.\\|^\\)\\(&\\)"
667 "\\(.\\|^\\)\\(#\\)"
668 "\\(.\\|^\\)\\(%\\)"
669 "\\(.\\|^\\)\\({\\)"
670 "\\(.\\|^\\)\\(}\\)"
671 "\\(.\\|^\\)\\(~\\)")))
673 (defun org-export-latex-treat-sub-super-char
674 (subsup string-before char string-after)
675 "Convert the \"_\" and \"^\" characters to LaTeX.
676 SUBSUP corresponds to the ^: option in the #+OPTIONS line.
677 Convert CHAR depending on STRING-BEFORE and STRING-AFTER."
678 (cond ((equal string-before "\\")
679 (concat string-before char string-after))
680 ;; this is part of a math formula
681 ((and (string-match "\\S-+" string-before)
682 (string-match "\\S-+" string-after))
683 (cond ((eq 'org-link (get-text-property 0 'face char))
684 ;; (cond ((get-text-property 0 'org-protected char)
685 (concat string-before "\\" char string-after))
686 ((save-match-data (org-inside-LaTeX-fragment-p))
687 (if subsup
688 (cond ((eq 1 (length string-after))
689 (concat string-before char string-after))
690 ((string-match "[({]?\\([^)}]+\\)[)}]?" string-after)
691 (format "%s%s{%s}" string-before char
692 (match-string 1 string-after))))))
693 ((and subsup
694 (> (length string-after) 1)
695 (string-match "[({]?\\([^)}]+\\)[)}]?" string-after))
696 (format "$%s%s{%s}$" string-before char
697 (match-string 1 string-after)))
698 (subsup (concat "$" string-before char string-after "$"))
699 (t (concat string-before char string-after))))
700 (t (concat string-before "\\" char string-after))))
702 (defun org-export-latex-treat-backslash-char (string-before string-after)
703 "Convert the \"$\" special character to LaTeX.
704 The conversion is made depending of STRING-BEFORE and STRING-AFTER."
705 (cond ((member (list string-after) org-html-entities)
706 ;; backslash is part of a special entity (like "\alpha")
707 (concat string-before "$\\"
708 (or (cdar (member (list string-after) org-html-entities))
709 string-after) "$"))
710 ((and (not (string-match "^[ \n\t]" string-after))
711 (not (string-match "[ \n\t]\\'" string-before)))
712 ;; backslash is inside a word
713 (concat string-before "$\\backslash$" string-after))
714 ((not (or (equal string-after "")
715 (string-match "^[ \t\n]" string-after)))
716 ;; backslash might escape a character (like \#) or a user TeX
717 ;; macro (like \setcounter)
718 (concat string-before "\\" string-after))
719 ((and (string-match "^[ \t\n]" string-after)
720 (string-match "[ \t\n]\\'" string-before))
721 ;; backslash is alone, convert it to $\backslash$
722 (concat string-before "$\\backslash$" string-after))
723 (t (concat string-before "$\\backslash$" string-after))))
725 (defun org-export-latex-fixed-width (opt)
726 "When OPT is non-nil convert fixed-width sections to LaTeX."
727 (goto-char (point-min))
728 (while (re-search-forward "^[ \t]*:" nil t)
729 (if opt
730 (progn (goto-char (match-beginning 0))
731 (insert "\\begin{verbatim}\n")
732 (while (looking-at "^\\([ \t]*\\):\\(.*\\)$")
733 (replace-match (concat (match-string 1)
734 (match-string 2)) t t)
735 (forward-line))
736 (insert "\\end{verbatim}\n\n"))
737 (progn (goto-char (match-beginning 0))
738 (while (looking-at "^\\([ \t]*\\):\\(.*\\)$")
739 (replace-match (concat "%" (match-string 1)
740 (match-string 2)) t t)
741 (forward-line))))))
743 (defun org-export-latex-tables (opt)
744 "When OPT is non-nil convert tables to LaTeX."
745 (goto-char (point-min))
746 (while (re-search-forward "^\\([ \t]*\\)|" nil t)
747 ;; Re-align the table to update org-table-last-alignment
748 (save-excursion (save-match-data (org-table-align)))
749 (let (tbl-list
750 (beg (match-beginning 0))
751 (end (save-excursion
752 (re-search-forward
753 (concat "^" (regexp-quote (match-string 1))
754 "[^|]\\|\\'") nil t) (match-beginning 0))))
755 (beginning-of-line)
756 (while (not (eq end (point)))
757 (if (looking-at "[ \t]*|\\([^-|].+\\)|[ \t]*$")
758 (push (split-string (org-trim (match-string 1)) "|") tbl-list)
759 (push 'hline tbl-list))
760 (forward-line))
761 ;; comment region out instead of deleting it ?
762 (apply 'delete-region (list beg end))
763 (when opt (insert (orgtbl-to-latex (nreverse tbl-list)
764 nil) "\n\n")))))
766 (defun org-export-latex-special-keywords ()
767 "Convert special keywords to LaTeX.
768 Regexps are those from `org-latex-special-string-regexps'."
769 (let ((rg org-latex-special-string-regexps) r)
770 (while (setq r (pop rg))
771 (goto-char (point-min))
772 (while (re-search-forward (eval r) nil t)
773 (replace-match (format "\\\\texttt{%s}" (match-string 0)) t)))))
775 ;; FIXME - we need better implementation for nested lists
776 (defun org-export-latex-list (srch0 srch1 srch2 rpl0 rpl1)
777 "Convert lists to LaTeX."
778 (goto-char (point-min))
779 (while (re-search-forward srch0 nil t)
780 (let* ((beg (match-beginning 0))
781 (prefix (regexp-quote (match-string 1)))
782 (end-string (when (re-search-forward srch1 nil t)
783 (match-string 0))))
784 (goto-char beg) (insert rpl0)
785 (while (re-search-forward
786 (concat "^" prefix srch2)
787 (if (not end-string)
788 (point-max)
789 (save-match-data
790 (save-excursion
791 (re-search-forward
792 (regexp-quote end-string) nil t)))) t)
793 (replace-match
794 (concat "\\item "
795 (if (match-string 1)
796 (format "\\texttt{%s}" (match-string 1))))
797 t t))
798 (goto-char (if end-string
799 (progn (re-search-forward
800 (regexp-quote end-string) nil t)
801 (match-beginning 0))
802 (point-max)))
803 (skip-chars-backward "\n") (forward-line 2)
804 (insert rpl1))))
806 (defun org-export-latex-itemize ()
807 "Convert item list to LaTeX."
808 (org-export-latex-list
809 "^\\([ \t]*\\)-"
810 "^[^ \n\t-]+.*$"
811 "- ?\\(\\[.+\\]\\)?"
812 "\\begin{itemize}\n"
813 "\\end{itemize}\n"))
815 (defun org-export-latex-enumerate ()
816 "Convert numeric list to LaTeX."
817 (org-export-latex-list
818 "^\\([ \t]*\\)[0-9]+[\.)] \\(\\[.+\\]\\)? ?"
819 "^[^ \n\t0-9]+.*$"
820 "[0-9]+[\.)] ?\\(\\[.+\\]\\)?"
821 "\\begin{enumerate}\n"
822 "\\end{enumerate}\n"))
824 (defun org-export-latex-fontify ()
825 "Convert fontification to LaTeX."
826 (goto-char (point-min))
827 (while (re-search-forward org-emph-re nil t)
828 ;; The match goes one char after the *string*
829 (unless (get-text-property (1- (point)) 'org-protected)
830 (replace-match
831 (concat (match-string 1)
832 (format
833 (org-export-latex-protect-char-in-string
834 '("\\" "{" "}")
835 (cadr (assoc (match-string 3)
836 org-export-latex-emphasis-alist)))
837 (match-string 4))
838 (match-string 5)) t t)
839 (backward-char))))
841 (defun org-export-latex-protect-char-in-string (char-list string)
842 "Add org-protected text-property to char from CHAR-LIST in STRING."
843 (with-temp-buffer
844 (save-match-data
845 (insert string)
846 (goto-char (point-min))
847 (while (re-search-forward (regexp-opt char-list) nil t)
848 (add-text-properties (match-beginning 0)
849 (match-end 0) '(org-protected t)))
850 (buffer-string))))
852 (defun org-export-latex-links ()
853 ;; Make sure to use the LaTeX hyperref and graphicx package
854 ;; or send some warnings.
855 "Convert links to LaTeX."
856 (goto-char (point-min))
857 (while (re-search-forward org-bracket-link-analytic-regexp nil t)
858 (org-if-unprotected
859 (goto-char (match-beginning 0))
860 (let* ((re-radio org-latex-all-targets-regexp)
861 (remove (list (match-beginning 0) (match-end 0)))
862 (type (match-string 2))
863 (raw-path (match-string 3))
864 (full-raw-path (concat (match-string 1) raw-path))
865 (desc (match-string 5))
866 imgp radiop
867 ;; define the path of the link
868 (path (cond
869 ((member type '("http" "https" "ftp"))
870 (concat type ":" raw-path))
871 ((and re-radio (string-match re-radio raw-path))
872 (setq radiop t))
873 ((equal type "mailto")
874 (concat type ":" raw-path))
875 ((equal type "file")
876 (if (and (or (org-file-image-p (expand-file-name raw-path))
877 (string-match "\\.eps$" raw-path))
878 (equal desc full-raw-path))
879 (setq imgp t)
880 (progn (when (string-match "\\(.+\\)::.+" raw-path)
881 (setq raw-path (match-string 1 raw-path)))
882 (if (file-exists-p raw-path)
883 (concat type "://" (expand-file-name raw-path))
884 (concat type "://" (org-export-directory
885 :LaTeX org-latex-options-plist)
886 raw-path))))))))
887 ;; process with link inserting
888 (apply 'delete-region remove)
889 (cond ((and imgp (plist-get org-latex-options-plist :inline-images))
890 (insert (format "\\includegraphics[%s]{%s}"
891 ;; image option should be set be a comment line
892 org-export-latex-image-default-option
893 (expand-file-name raw-path))))
894 ;; FIXME: what about caption? image properties?
895 (radiop (insert (format "\\hyperref[%s]{%s}" raw-path desc)))
896 (path (insert (format "\\href{%s}{%s}" path desc)))
897 (t (insert "\\texttt{" desc "}")))))))
900 (defun org-latex-cleaned-string-for-export (string &rest parameters)
901 "Cleanup a buffer STRING so that links can be created safely."
902 (interactive)
903 (let* ((re-radio (and org-target-link-regexp
904 (concat "\\([^<]\\)\\(" org-target-link-regexp "\\)")))
905 (re-plain-link (concat "\\([^[<]\\)" org-plain-link-re))
906 (re-angle-link (concat "\\([^[]\\)" org-angle-link-re))
907 (re-archive (concat ":" org-archive-tag ":"))
908 (re-quote (concat "^\\*+[ \t]+" org-quote-string "\\>"))
909 (htmlp (plist-get parameters :for-html))
910 (latexp (plist-get parameters :for-LaTeX))
911 (commentsp (plist-get parameters :comments))
912 (inhibit-read-only t)
913 (outline-regexp "\\*+ ")
914 a b xx
915 rtn p)
916 (save-excursion
917 (set-buffer (get-buffer-create " org-mode-tmp"))
918 (erase-buffer)
919 (insert string)
920 ;; Remove license-to-kill stuff
921 (while (setq p (text-property-any (point-min) (point-max)
922 :org-license-to-kill t))
923 (delete-region p (next-single-property-change p :org-license-to-kill)))
925 (let ((org-inhibit-startup t)) (org-mode))
926 (untabify (point-min) (point-max))
928 ;; Get the correct stuff before the first headline
929 (when (plist-get parameters :skip-before-1st-heading)
930 (goto-char (point-min))
931 (when (re-search-forward "^\\*+[ \t]" nil t)
932 (delete-region (point-min) (match-beginning 0))
933 (goto-char (point-min))
934 (insert "\n")))
935 (when (plist-get parameters :add-text)
936 (goto-char (point-min))
937 (insert (plist-get parameters :add-text) "\n"))
939 ;; Get rid of archived trees
940 (when (not (eq org-export-with-archived-trees t))
941 (goto-char (point-min))
942 (while (re-search-forward re-archive nil t)
943 (if (not (org-on-heading-p t))
944 (org-end-of-subtree t)
945 (beginning-of-line 1)
946 (setq a (if org-export-with-archived-trees
947 (1+ (point-at-eol)) (point))
948 b (org-end-of-subtree t))
949 (if (> b a) (delete-region a b)))))
951 ;; Get rid of property drawers
952 (unless org-export-with-property-drawer
953 (goto-char (point-min))
954 (while (re-search-forward "^[ \t]*:PROPERTIES:[ \t]*\n\\([^@]*?\n\\)?[ \t]*:END:[ \t]*\n" nil t)
955 (replace-match "")))
957 ;; Find targets in comments and move them out of comments,
958 ;; but mark them as targets that should be invisible
959 (goto-char (point-min))
960 (while (re-search-forward "^#.*?\\(<<<?[^>\r\n]+>>>?\\).*" nil t)
961 (replace-match "\\1(INVISIBLE)"))
963 ;; Specific LaTeX cleaning
964 (when latexp
965 (require 'org-export-latex nil t)
966 (org-export-latex-cleaned-string))
968 ;; Protect stuff from HTML processing
969 (goto-char (point-min))
970 (let ((formatters `((,htmlp "HTML" "BEGIN_HTML" "END_HTML"))) fmt)
971 (while (re-search-forward "^[ \t]*:.*\\(\n[ \t]*:.*\\)*" nil t)
972 (add-text-properties (match-beginning 0) (match-end 0)
973 '(org-protected t)))
974 (while formatters
975 (setq fmt (pop formatters))
976 (when (car fmt)
977 (goto-char (point-min))
978 (while (re-search-forward (concat "^#\\+" (cadr fmt)
979 ":[ \t]*\\(.*\\)") nil t)
980 (replace-match "\\1" t)
981 (add-text-properties
982 (point-at-bol) (min (1+ (point-at-eol)) (point-max))
983 '(org-protected t))))
984 (goto-char (point-min))
985 (while (re-search-forward
986 (concat "^#\\+"
987 (caddr fmt) "\\>.*\\(\\(\n.*\\)*?\n\\)#\\+"
988 (cadddr fmt) "\\>.*\n?") nil t)
989 (if (car fmt)
990 (add-text-properties (match-beginning 1) (1+ (match-end 1))
991 '(org-protected t))
992 (delete-region (match-beginning 0) (match-end 0))))
993 (goto-char (point-min))
994 (while (re-search-forward re-quote nil t)
995 (goto-char (match-beginning 0))
996 (end-of-line 1)
997 (add-text-properties (point) (org-end-of-subtree t)
998 '(org-protected t)))))
1000 ;; Remove or replace comments
1001 ;; If :comments is set, use this char for commenting out comments and
1002 ;; protect them. otherwise delete them
1003 (goto-char (point-min))
1004 (while (re-search-forward "^#\\(.*\n?\\)" nil t)
1005 (if commentsp
1006 (progn (add-text-properties
1007 (match-beginning 0) (match-end 0) '(org-protected t))
1008 (replace-match (format commentsp (match-string 1)) t t))
1009 (replace-match "")))
1011 ;; Find matches for radio targets and turn them into internal links
1012 (goto-char (point-min))
1013 (when re-radio
1014 (while (re-search-forward re-radio nil t)
1015 (org-if-unprotected
1016 (replace-match "\\1[[\\2]]"))))
1018 ;; Find all links that contain a newline and put them into a single line
1019 (goto-char (point-min))
1020 (while (re-search-forward "\\(\\(\\[\\|\\]\\)\\[[^]]*?\\)[ \t]*\n[ \t]*\\([^]]*\\]\\(\\[\\|\\]\\)\\)" nil t)
1021 (org-if-unprotected
1022 (replace-match "\\1 \\3")
1023 (goto-char (match-beginning 0))))
1025 ;; Convert LaTeX fragments to images
1026 (when (plist-get parameters :LaTeX-fragments)
1027 (org-format-latex
1028 (concat "ltxpng/" (file-name-sans-extension
1029 (file-name-nondirectory
1030 org-current-export-file)))
1031 org-current-export-dir nil "Creating LaTeX image %s"))
1032 (message "Exporting...")
1034 ;; Normalize links: Convert angle and plain links into bracket links
1035 ;; Expand link abbreviations
1036 (goto-char (point-min))
1037 (while (re-search-forward re-plain-link nil t)
1038 (goto-char (1- (match-end 0)))
1039 (org-if-unprotected
1040 (let* ((s (concat (match-string 1) "[[" (match-string 2)
1041 ":" (match-string 3) "]]")))
1042 ;; added 'org-protected property to links
1043 (put-text-property 0 (length s) 'face 'org-link s)
1044 ;; (add-text-properties 0 (length s) '(org-protected t) s)
1045 (replace-match s t t))))
1046 (goto-char (point-min))
1047 (while (re-search-forward re-angle-link nil t)
1048 (goto-char (1- (match-end 0)))
1049 (org-if-unprotected
1050 (let* ((s (concat (match-string 1) "[[" (match-string 2)
1051 ":" (match-string 3) "]]")))
1052 (put-text-property 0 (length s) 'face 'org-link s)
1053 ;; (add-text-properties 0 (length s) '(org-protected t) s)
1054 (replace-match s t t))))
1055 (goto-char (point-min))
1056 (while (re-search-forward org-bracket-link-regexp nil t)
1057 (org-if-unprotected
1058 (let* ((s (concat "[[" (setq xx (save-match-data
1059 (org-link-expand-abbrev (match-string 1))))
1061 (if (match-end 3)
1062 (match-string 2)
1063 (concat "[" xx "]"))
1064 "]")))
1065 (put-text-property 0 (length s) 'face 'org-link s)
1066 ;; (add-text-properties 0 (length s) '(org-protected t) s)
1067 (replace-match s t t))))
1069 ;; Find multiline emphasis and put them into single line
1070 (when (plist-get parameters :emph-multiline)
1071 (goto-char (point-min))
1072 (while (re-search-forward org-emph-re nil t)
1073 (if (not (= (char-after (match-beginning 3))
1074 (char-after (match-beginning 4))))
1075 (org-if-unprotected
1076 (subst-char-in-region (match-beginning 0) (match-end 0)
1077 ?\n ?\ t)
1078 (goto-char (1- (match-end 0))))
1079 (goto-char (1+ (match-beginning 0))))))
1081 (setq rtn (buffer-string)))
1082 (kill-buffer " org-mode-tmp")
1083 rtn))
1085 (defsubst org-latex-protect (string)
1086 (add-text-properties 0 (length string) '(org-protected t) string)
1087 string)
1089 (defun org-export-latex-cleaned-string ()
1090 "Clean stuff in the LaTeX export."
1092 ;; preserve line breaks
1093 (goto-char (point-min))
1094 (while (re-search-forward "\\\\\\\\" nil t)
1095 (add-text-properties (match-beginning 0) (match-end 0)
1096 '(org-protected t)))
1098 ;; convert LaTeX to @LaTeX{}
1099 (goto-char (point-min))
1100 (let ((case-fold-search nil) rpl)
1101 (while (re-search-forward "\\([^+_]\\)LaTeX" nil t)
1102 (replace-match (org-latex-protect
1103 (concat (match-string 1) "\\LaTeX{}")) t t)))
1105 ;; convert horizontal rules
1106 (goto-char (point-min))
1107 (while (re-search-forward "^----+.$" nil t)
1108 (replace-match (org-latex-protect "\\hrule") t t))
1110 ;; Remove COMMENT subtrees
1111 ;; What about QUOTE subtrees?
1112 (goto-char (point-min))
1113 (while (re-search-forward
1114 (concat "^\\*+ \\(" org-comment-string "\\)")
1115 nil t)
1116 (beginning-of-line)
1117 (org-cut-subtree))
1119 ;; protect LaTeX \commands{...}
1120 (goto-char (point-min))
1121 (while (re-search-forward "\\\\[a-z]+{.+}" nil t)
1122 (add-text-properties (match-beginning 0) (match-end 0)
1123 '(org-protected t)))
1125 ;; Replace radio links
1126 (goto-char (point-min))
1127 (let ((search (concat "<<<?" org-latex-all-targets-regexp ">?>>")))
1128 (while (re-search-forward search nil t)
1129 (replace-match
1130 (org-latex-protect (format "\\label{%s}" (match-string 1))) t t)))
1132 ;; delete @<br /> cookies
1133 (goto-char (point-min))
1134 (while (re-search-forward "@<[^<>\n]*>" nil t)
1135 (replace-match ""))
1137 ;; add #+BEGIN_LaTeX before any \begin{...}
1138 (goto-char (point-min))
1139 (while (re-search-forward "^ *\\\\begin{" nil t)
1140 (replace-match "#+BEGIN_LaTeX:\n\\&" t))
1142 ;; add #+END_LaTeX after any \end{...}
1143 (goto-char (point-min))
1144 (while (re-search-forward "^ *\\\\end{.+}.*$" nil t)
1145 (replace-match "\\&\n#+END_LaTeX" t))
1147 ;; When converting to LaTeX, replace footnotes
1148 ;; FIXME: don't protect footnotes from conversion
1149 (when (plist-get org-latex-options-plist :footnotes)
1150 (goto-char (point-min))
1151 (while (re-search-forward "\\[[0-9]+\\]" nil t)
1152 (when (save-match-data
1153 (save-excursion (beginning-of-line)
1154 (looking-at "[^:|]")))
1155 (let ((foot-beg (match-beginning 0))
1156 (foot-end (match-end 0))
1157 (foot-prefix (match-string 0))
1158 footnote footnote-rpl)
1159 (when (and (re-search-forward (regexp-quote foot-prefix) nil t))
1160 (replace-match "")
1161 (let ((end (save-excursion
1162 (if (re-search-forward "^$\\|\\[[0-9]+\\]" nil t)
1163 (match-beginning 0) (point-max)))))
1164 (setq footnote (concat
1165 (org-trim (buffer-substring (point) end))
1166 ;; FIXME stupid workaround for cases where
1167 ;; `org-bracket-link-analytic-regexp' matches
1168 ;; }. as part of the link.
1169 " "))
1170 (delete-region (point) end)))
1171 (goto-char foot-beg)
1172 (delete-region foot-beg foot-end)
1173 (setq footnote-rpl (format "\\footnote{%s}" footnote))
1174 ;; FIXME Remove
1175 ;; (add-text-properties 0 1 '(org-protected t) footnote-rpl)
1176 (add-text-properties 0 10 '(org-protected t) footnote-rpl)
1177 ;; FIXME: why protecting the content of a footnote?
1178 (add-text-properties (1- (length footnote-rpl))
1179 (length footnote-rpl)
1180 '(org-protected t) footnote-rpl)
1181 (insert footnote-rpl))))
1183 ;; Replace footnote section tag for LaTeX
1184 (goto-char (point-min))
1185 (while (re-search-forward
1186 (concat "^" footnote-section-tag-regexp) nil t)
1187 (replace-match "")))
1189 ;; Protect stuff from LaTeX processing.
1190 ;; We will get rid on this once org.el integrate org-export-latex.el
1191 ;; FIXME: #+LaTeX should be aware of the preceeding indentation in lists
1192 (goto-char (point-min))
1193 (let ((formatters `((,latexp "LaTeX" "BEGIN_LaTeX" "END_LaTeX"))) fmt)
1194 (while (re-search-forward "^[ \t]*:.*\\(\n[ \t]*:.*\\)*" nil t)
1195 (add-text-properties (match-beginning 0) (match-end 0)
1196 '(org-protected t)))
1197 (while formatters
1198 (setq fmt (pop formatters))
1199 (when (car fmt)
1200 (goto-char (point-min))
1201 (while (re-search-forward (concat "^#\\+" (cadr fmt)
1202 ":[ \t]*\\(.*\\)") nil t)
1203 (replace-match "\\1" t)
1204 (add-text-properties
1205 (point-at-bol) (min (1+ (point-at-eol)) (point-max))
1206 '(org-protected t))))
1207 (goto-char (point-min))
1208 (while (re-search-forward
1209 (concat "^#\\+"
1210 (caddr fmt) "\\>.*\\(\\(\n.*\\)*?\n\\)#\\+"
1211 (cadddr fmt) "\\>.*\n?") nil t)
1212 (if (car fmt)
1213 (add-text-properties (match-beginning 1) (1+ (match-end 1))
1214 '(org-protected t))
1215 (delete-region (match-beginning 0) (match-end 0))))
1216 (goto-char (point-min))
1217 (while (re-search-forward re-quote nil t)
1218 (goto-char (match-beginning 0))
1219 (end-of-line 1)
1220 (add-text-properties (point) (org-end-of-subtree t)
1221 '(org-protected t))))))
1223 (provide 'org-export-latex)
1225 ;;; org-export-latex.el ends here