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