diff lisp/textmodes/org-export-latex.el @ 84384:a32093d94b4a

Updated to org-mode 5.08
author John Wiegley <johnw@newartisans.com>
date Fri, 07 Sep 2007 20:16:46 +0000
parents 1d75f075c32a
children 380656116258
line wrap: on
line diff
--- a/lisp/textmodes/org-export-latex.el	Fri Sep 07 20:04:58 2007 +0000
+++ b/lisp/textmodes/org-export-latex.el	Fri Sep 07 20:16:46 2007 +0000
@@ -3,27 +3,29 @@
 ;;
 ;; Author: Bastien Guerry <bzg AT altern DOT org>
 ;; Keywords: org organizer latex export convert
+;; Version: $Id: org-export-latex.el,v 0.28a 2007/08/31 06:22:06 guerry Exp guerry $
 ;; X-URL: <http://www.cognition.ens.fr/~guerry/u/org-export-latex.el>
 ;;
 ;; This file is part of GNU Emacs.
 ;;
-;; This program is free software; you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
+;; GNU Emacs is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by the
+;; Free Software Foundation; either version 3, or (at your option) any
+;; later version.
 ;;
-;; This program is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-;; GNU General Public License for more details.
+;; GNU Emacs is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+;; more details.
+;; 
+;; You should have received a copy of the GNU General Public License along
+;; with GNU Emacs; see the file COPYING. If not, write to the Free Software
+;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+;; 02110-1301, USA.
 ;;
-;; You should have received a copy of the GNU General Public License
-;; along with this program; if not, write to the Free Software
-;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
 ;;; Commentary:
-
-;; This library is a LaTeX exporter for org-mode.
+;;
+;; This library implements a LaTeX exporter for org-mode.
 ;; 
 ;; Put this file into your load-path and the following into your ~/.emacs:
 ;;   (require 'org-export-latex)
@@ -35,18 +37,16 @@
 ;; M-x `org-export-as-latex-to-buffer'
 ;; M-x `org-export-region-as-latex'
 ;; M-x `org-replace-region-by-latex'
-
-;;; History:
-;; 
-;; I started this piece of code in may 2007. Special thanks to Carsten
-;; Dominik for helping me on this.
-;; 
-
+;;
 ;;; Code:
 
-(require 'org)
+(eval-when-compile
+  (require 'cl))
+
 (require 'footnote)
+(require 'org)
 
+;;; Variables:
 (defvar org-latex-options-plist nil)
 (defvar org-latex-todo-keywords-1 nil)
 (defvar org-latex-all-targets-regexp nil)
@@ -60,6 +60,11 @@
     org-clock-string)
   "A list of regexps to convert as special keywords.")
 
+(defvar latexp)    ; dynamically scoped from org.el
+(defvar re-quote)  ; dynamically scoped from org.el
+(defvar commentsp) ; dynamically scoped from org.el
+
+;;; Custom variables:
 (defcustom org-export-latex-sectioning-alist
   '((1 "\\section{%s}" "\\section*{%s}")
     (2 "\\subsection{%s}" "\\subsection*{%s}")
@@ -150,6 +155,8 @@
 ;; FIXME Do we want this one?
 ;; (defun org-export-as-latex-and-open (arg) ...)
 
+
+;;; Autoload functions:
 ;;;###autoload
 (defun org-export-as-latex-batch ()
   "Call `org-export-as-latex', may be used in batch processing as
@@ -283,6 +290,7 @@
 		  :LaTeX-fragments nil)))
     (set-buffer buffer)
     (erase-buffer)
+
     (unless body-only (insert preamble))
     (when text (insert (org-export-latex-content text) "\n\n"))
     (unless skip (insert first-lines))
@@ -305,7 +313,7 @@
 	 (org-export-latex-parse-global level odd))))
 
     (unless body-only (insert "\n\\end{document}"))
-    (or to-buffer (write-file filename))
+    (or to-buffer (save-buffer))
     (goto-char (point-min))
     (message "Exporting to LaTeX...done")
     (if (eq to-buffer 'string)
@@ -313,6 +321,140 @@
 	  (kill-buffer (current-buffer)))
       (current-buffer))))
 
+
+;;; Parsing functions:
+(defun org-export-latex-parse-global (level odd)
+  "Parse the current buffer recursively, starting at LEVEL.
+If ODD is non-nil, assume the buffer only contains odd sections.
+Return A list reflecting the document structure."
+  (save-excursion
+    (goto-char (point-min))
+    (let* ((cnt 0) output
+	   (depth org-latex-sectioning-depth))
+      (while (re-search-forward
+	      (concat "^\\(\\(?:\\*\\)\\{"
+		      (number-to-string (+ (if odd 2 1) level))
+		      "\\}\\) \\(.*\\)$")
+	      ;; make sure that there is no upper heading
+	      (when (> level 0)
+		(save-excursion
+		  (save-match-data
+		    (re-search-forward
+		     (concat "^\\(\\(?:\\*\\)\\{"
+			     (number-to-string level)
+			     "\\}\\) \\(.*\\)$") nil t)))) t)
+	(setq cnt (1+ cnt))
+	(let* ((pos (match-beginning 0))
+	       (heading (match-string 2))
+	       (nlevel (if odd (/ (+ 3 level) 2) (1+ level))))
+	  (save-excursion
+	    (narrow-to-region
+	     (point)
+	     (save-match-data
+	       (if (re-search-forward
+		    (concat "^\\(\\(?:\\*\\)\\{"
+			    (number-to-string (+ (if odd 2 1) level))
+			    "\\}\\) \\(.*\\)$") nil t)
+		   (match-beginning 0)
+		 (point-max))))
+	    (goto-char (point-min))
+	    (setq output
+		  (append output
+			  (list
+			   (list
+			    `(pos . ,pos)
+			    `(level . ,nlevel)
+			    `(occur . ,cnt)
+			    `(heading . ,heading)
+			    `(content . ,(org-export-latex-parse-content))
+			    `(subcontent . ,(org-export-latex-parse-subcontent 
+					     level odd)))))))
+	  (widen)))
+      (list output))))
+
+(defun org-export-latex-parse-content ()
+  "Extract the content of a section."
+  (let ((beg (point))
+	(end (if (re-search-forward "^\\(\\*\\)+ .*$" nil t)
+		 (progn (beginning-of-line) (point))
+	       (point-max))))
+    (buffer-substring beg end)))
+
+(defun org-export-latex-parse-subcontent (level odd)
+  "Extract the subcontent of a section at LEVEL.
+If ODD Is non-nil, assume subcontent only contains odd sections."
+  (if (not (re-search-forward
+	    (concat "^\\(\\(?:\\*\\)\\{"
+		    (number-to-string (+ (if odd 4 2) level))
+		    "\\}\\) \\(.*\\)$")
+	    nil t))
+      nil ; subcontent is nil
+    (org-export-latex-parse-global (+ (if odd 2 1) level) odd)))
+
+
+;;; Rendering functions:
+(defun org-export-latex-global (content)
+  "Export CONTENT to LaTeX.
+CONTENT is an element of the list produced by
+`org-export-latex-parse-global'."
+  (if (eq (car content) 'subcontent)
+      (mapc 'org-export-latex-sub (cdr content))
+    (org-export-latex-sub (car content))))
+
+(defun org-export-latex-sub (subcontent)
+  "Export the list SUBCONTENT to LaTeX.
+SUBCONTENT is an alist containing information about the headline
+and its content."
+  (mapc (lambda(x) (org-export-latex-subcontent x)) subcontent))
+
+(defun org-export-latex-subcontent (subcontent)
+  "Export each cell of SUBCONTENT to LaTeX."
+  (let ((heading (org-export-latex-fontify-headline
+		  (cdr (assoc 'heading subcontent))))
+	(level (- (cdr (assoc 'level subcontent))
+		  org-latex-add-level))
+	(occur (number-to-string (cdr (assoc 'occur subcontent))))
+	(content (cdr (assoc 'content subcontent)))
+	(subcontent (cadr (assoc 'subcontent subcontent)))
+	(num (plist-get org-latex-options-plist :section-numbers)))
+    (cond 
+     ;; Normal conversion
+     ((<= level org-latex-sectioning-depth)
+      (let ((sec (assoc level org-export-latex-sectioning-alist)))
+	(insert (format (if num (cadr sec) (caddr sec)) heading) "\n"))
+      (insert (org-export-latex-content content))
+      (cond ((stringp subcontent) (insert subcontent))
+	    ((listp subcontent) (org-export-latex-sub subcontent))))
+     ;; At a level under the hl option: we can drop this subsection
+     ((> level org-latex-sectioning-depth)
+      (cond ((eq org-export-latex-low-levels 'description)
+	     (insert (format "\\begin{description}\n\n\\item[%s]\n\n" heading))
+	     (insert (org-export-latex-content content))
+	     (cond ((stringp subcontent) (insert subcontent))
+		   ((listp subcontent) (org-export-latex-sub subcontent)))
+	     (insert "\\end{description}\n"))
+	    ((stringp org-export-latex-low-levels)
+	     (insert (format org-export-latex-low-levels heading) "\n")
+	     (insert (org-export-latex-content content))
+	     (cond ((stringp subcontent) (insert subcontent))
+		   ((listp subcontent) (org-export-latex-sub subcontent)))))))))
+
+
+;;; Exporting internals:
+(defun org-latex-protect (string)
+  (add-text-properties 0 (length string) '(org-protected t) string) string)
+
+(defun org-export-latex-protect-char-in-string (char-list string)
+  "Add org-protected text-property to char from CHAR-LIST in STRING."
+  (with-temp-buffer
+    (save-match-data
+      (insert string)
+      (goto-char (point-min))
+      (while (re-search-forward (regexp-opt char-list) nil t)
+	(add-text-properties (match-beginning 0)
+			     (match-end 0) '(org-protected t)))
+      (buffer-string))))
+
 (defun org-export-latex-set-initial-vars (ext-plist)
   "Store org local variables required for LaTeX export.
 EXT-PLIST is an optional additional plist."
@@ -395,121 +537,7 @@
 	:skip-before-1st-heading nil
 	:LaTeX-fragments nil)))))
 
-(defun org-export-latex-parse-global (level odd)
-  "Parse the current buffer recursively, starting at LEVEL.
-If ODD is non-nil, assume the buffer only contains odd sections.
-Return A list reflecting the document structure."
-  (save-excursion
-    (goto-char (point-min))
-    (let* ((cnt 0) output
-	   (depth org-latex-sectioning-depth))
-      (while (re-search-forward
-	      (concat "^\\(\\(?:\\*\\)\\{"
-		      (number-to-string (+ (if odd 2 1) level))
-		      "\\}\\) \\(.*\\)$")
-	      ;; make sure that there is no upper heading
-	      (when (> level 0)
-		(save-excursion
-		  (save-match-data
-		    (re-search-forward
-		     (concat "^\\(\\(?:\\*\\)\\{"
-			     (number-to-string level)
-			     "\\}\\) \\(.*\\)$") nil t)))) t)
-	(setq cnt (1+ cnt))
-	(let* ((pos (match-beginning 0))
-	       (heading (match-string 2))
-	       (nlevel (if odd (/ (+ 3 level) 2) (1+ level))))
-	  (save-excursion
-	    (narrow-to-region
-	     (point)
-	     (save-match-data
-	       (if (re-search-forward
-		    (concat "^\\(\\(?:\\*\\)\\{"
-			    (number-to-string (+ (if odd 2 1) level))
-			    "\\}\\) \\(.*\\)$") nil t)
-		   (match-beginning 0)
-		 (point-max))))
-	    (goto-char (point-min))
-	    (setq output
-		  (append output
-			  (list
-			   (list
-			    `(pos . ,pos)
-			    `(level . ,nlevel)
-			    `(occur . ,cnt)
-			    `(heading . ,heading)
-			    `(content . ,(org-export-latex-parse-content))
-			    `(subcontent . ,(org-export-latex-parse-subcontent 
-					     level odd)))))))
-	  (widen)))
-      (list output))))
-
-(defun org-export-latex-parse-content ()
-  "Extract the content of a section."
-  (let ((beg (point))
-	(end (if (re-search-forward "^\\(\\*\\)+ .*$" nil t)
-		 (progn (beginning-of-line) (point))
-	       (point-max))))
-    (buffer-substring beg end)))
-
-(defun org-export-latex-parse-subcontent (level odd)
-  "Extract the subcontent of a section at LEVEL.
-If ODD Is non-nil, assume subcontent only contains odd sections."
-  (if (not (re-search-forward
-	    (concat "^\\(\\(?:\\*\\)\\{"
-		    (number-to-string (+ (if odd 4 2) level))
-		    "\\}\\) \\(.*\\)$")
-	    nil t))
-      nil ; subcontent is nil
-    (org-export-latex-parse-global (+ (if odd 2 1) level) odd)))
-
-(defun org-export-latex-global (content)
-  "Export CONTENT to LaTeX.
-CONTENT is an element of the list produced by
-`org-export-latex-parse-global'."
-  (if (eq (car content) 'subcontent)
-      (mapc 'org-export-latex-sub (cdr content))
-    (org-export-latex-sub (car content))))
-
-(defun org-export-latex-sub (subcontent)
-  "Export the list SUBCONTENT to LaTeX.
-SUBCONTENT is an alist containing information about the headline
-and its content."
-  (mapc (lambda(x) (org-export-latex-subcontent x)) subcontent))
-
-(defun org-export-latex-subcontent (subcontent)
-  "Export each cell of SUBCONTENT to LaTeX."
-  (let ((heading (org-export-latex-fontify-headline
-		  (cdr (assoc 'heading subcontent))))
-	(level (- (cdr (assoc 'level subcontent))
-		  org-latex-add-level))
-	(occur (number-to-string (cdr (assoc 'occur subcontent))))
-	(content (cdr (assoc 'content subcontent)))
-	(subcontent (cadr (assoc 'subcontent subcontent)))
-	(num (plist-get org-latex-options-plist :section-numbers)))
-    (cond 
-     ;; Normal conversion
-     ((<= level org-latex-sectioning-depth)
-      (let ((sec (assoc level org-export-latex-sectioning-alist)))
-	(insert (format (if num (cadr sec) (caddr sec)) heading) "\n"))
-      (insert (org-export-latex-content content))
-      (cond ((stringp subcontent) (insert subcontent))
-	    ((listp subcontent) (org-export-latex-sub subcontent))))
-     ;; At a level under the hl option: we can drop this subsection
-     ((> level org-latex-sectioning-depth)
-      (cond ((eq org-export-latex-low-levels 'description)
-	     (insert (format "\\begin{description}\n\n\\item[%s]\n\n" heading))
-	     (insert (org-export-latex-content content))
-	     (cond ((stringp subcontent) (insert subcontent))
-		   ((listp subcontent) (org-export-latex-sub subcontent)))
-	     (insert "\\end{description}\n"))
-	    ((stringp org-export-latex-low-levels)
-	     (insert (format org-export-latex-low-levels heading) "\n")
-	     (insert (org-export-latex-content content))
-	     (cond ((stringp subcontent) (insert subcontent))
-		   ((listp subcontent) (org-export-latex-sub subcontent)))))))))
-
-(defun org-export-latex-special-keywords-maybe (remove-list)
+(defun org-export-latex-keywords-maybe (remove-list)
   "Maybe remove keywords depending on rules in REMOVE-LIST."
   (goto-char (point-min))
   (let ((re-todo (mapconcat 'identity org-latex-todo-keywords-1 "\\|")))
@@ -525,7 +553,8 @@
 	(replace-match (format "\\texttt{%s}" (match-string 0)) t t)))
     ;; convert tags
     (when (re-search-forward "\\(:[a-zA-Z0-9]+\\)+:" nil t)
-      (if (plist-get remove-list :tags)
+      (if (or (not org-export-with-tags)
+	      (plist-get remove-list :tags))
 	  (replace-match "")
 	(replace-match (format "\\texttt{%s}" (match-string 0)) t t)))))
 
@@ -536,40 +565,41 @@
     ;; the beginning of the buffer - inserting "\n" is safe here though.
     (insert "\n" headline)
     (goto-char (point-min))
-    (org-export-latex-fontify)
     (org-export-latex-special-chars
      (plist-get org-latex-options-plist :sub-superscript))
-    (org-export-latex-special-keywords-maybe
+    (when (plist-get org-latex-options-plist :emphasize)
+      (org-export-latex-fontify))
+    (org-export-latex-keywords-maybe
      org-export-latex-remove-from-headines)
     (org-export-latex-links)
     (org-trim (buffer-substring-no-properties (point-min) (point-max)))))
 
+(defun org-export-latex-fix-invisible-strings ()
+  "Comment out (INVISIBLE) warnings."
+  (goto-char (point-min))
+  (while (re-search-forward "(INVISIBLE)" nil t)
+    (replace-match "%\\&")))
+
 (defun org-export-latex-content (content)
   "Convert CONTENT string to LaTeX."
   (with-temp-buffer
    (insert content)
    (org-export-latex-quotation-marks)
+   (org-export-latex-special-chars
+    (plist-get org-latex-options-plist :sub-superscript))
    (when (plist-get org-latex-options-plist :emphasize)
      (org-export-latex-fontify))
-   (org-export-latex-special-chars
-    (plist-get org-latex-options-plist :sub-superscript))
    (org-export-latex-links)
-   (org-export-latex-special-keywords)
+   (org-export-latex-keywords)
    (org-export-latex-itemize)
    (org-export-latex-enumerate)
    (org-export-latex-tables
     (plist-get org-latex-options-plist :tables))
    (org-export-latex-fixed-width
     (plist-get org-latex-options-plist :fixed-width))
-   (org-export-fix-invisible-strings)
+   (org-export-latex-fix-invisible-strings)
    (buffer-substring (point-min) (point-max))))
 
-(defun org-export-fix-invisible-strings ()
-  "Comment out (INVISIBLE) warnings."
-  (goto-char (point-min))
-  (while (re-search-forward "(INVISIBLE)" nil t)
-    (replace-match "%\\&")))
-
 (defun org-export-latex-quotation-marks ()
   "Export question marks depending on language conventions.
 Local definition of the language overrides
@@ -628,11 +658,12 @@
 		      (replace-match (concat (match-string 1) "\\"
 					     (match-string 2)) t t)))
 		   ((equal (match-string 2) "~")
-		    (unless (get-text-property 0 'org-protected (match-string 2))
-		      (if (equal (match-string 1) "\\") nil
-			(replace-match 
-			 (org-latex-protect
-			  (concat (match-string 1) "\\textasciitilde{}")) t t))))
+		      (cond ((equal (match-string 1) "\\") nil)
+			    ((eq 'org-link (get-text-property 0 'face (match-string 2)))
+			     (replace-match (concat (match-string 1) "\\~") t t))
+			    (t (replace-match 
+				(org-latex-protect
+				 (concat (match-string 1) "\\~{}")) t t))))
 		   ((member (match-string 2) '("{" "}"))
 		    (unless (save-match-data (org-inside-LaTeX-fragment-p))
 		      (if (equal (match-string 1) "\\")
@@ -653,8 +684,8 @@
 					    (match-string 2)
 					    (match-string 3))) "") t t)))))))
 	'("^\\([^\n$]*?\\|^\\)\\(\\\\?\\$\\)\\([^\n$]*\\)$"
- 	  "\\([a-za-z0-9]+\\|[ \t\n]\\|\\\\\\)\\(_\\|\\^\\)\\([a-za-z0-9]+\\|[ \t\n]\\|[:punct:]\\|{[a-za-z0-9]+}\\|([a-za-z0-9]+)\\)"
-	  "\\(.\\|^\\)\\(\\\\\\)\\([ \t\n]\\|[a-za-z&#%{}]+\\)"
+ 	  "\\([a-za-z0-9]+\\|[ \t\n]\\|\\b\\|\\\\\\)\\(_\\|\\^\\)\\([a-za-z0-9]+\\|[ \t\n]\\|[:punct:]\\|{[a-za-z0-9]+}\\|([a-za-z0-9]+)\\)"
+	  "\\(.\\|^\\)\\(\\\\\\)\\([ \t\n]\\|[a-zA-Z&#%{}\"]+\\)"
 	  "\\(.\\|^\\)\\(&\\)"
  	  "\\(.\\|^\\)\\(#\\)"
  	  "\\(.\\|^\\)\\(%\\)"
@@ -672,7 +703,7 @@
 	;; this is part of a math formula
 	((and (string-match "\\S-+" string-before)
 	      (string-match "\\S-+" string-after))
-	 (cond ((get-text-property 0 'org-protected char)
+	 (cond ((eq 'org-link (get-text-property 0 'face char))
 		(concat string-before "\\" char string-after))
 	       ((save-match-data (org-inside-LaTeX-fragment-p))
 		(if subsup
@@ -681,13 +712,13 @@
 			  ((string-match "[({]?\\([^)}]+\\)[)}]?" string-after)
 			   (format "%s%s{%s}" string-before char 
 				   (match-string 1 string-after))))))
-	       ((and subsup 
+	       ((and subsup
 		     (> (length string-after) 1)
 		     (string-match "[({]?\\([^)}]+\\)[)}]?" string-after))
 		(format "$%s%s{%s}$" string-before char
 			(match-string 1 string-after)))
-	  (subsup (concat "$" string-before char string-after "$"))
-	  (t (concat string-before char string-after))))
+	       (subsup (concat "$" string-before char string-after "$"))
+	       (t (concat string-before "\\" char string-after))))
 	(t (concat string-before "\\" char string-after))))
 
 (defun org-export-latex-treat-backslash-char (string-before string-after)
@@ -699,7 +730,7 @@
 		 (or (cdar (member (list string-after) org-html-entities))
 		     string-after) "$"))
 	((and (not (string-match "^[ \n\t]" string-after))
-	      (not (string-match "[ \n\t]\\'" string-before)))
+	      (not (string-match "[ \t]\\'\\|^" string-before)))
 	 ;; backslash is inside a word
 	 (concat string-before "$\\backslash$" string-after))
 	((not (or (equal string-after "")
@@ -713,6 +744,16 @@
 	 (concat string-before "$\\backslash$" string-after))
 	(t (concat string-before "$\\backslash$" string-after))))
 
+(defun org-export-latex-keywords ()
+  "Convert special keywords to LaTeX.
+Regexps are those from `org-latex-special-string-regexps'."
+  (let ((rg org-latex-special-string-regexps) r)
+    (while (setq r (pop rg))
+      (goto-char (point-min))
+      (while (re-search-forward (eval r) nil t)
+	(replace-match (format "\\\\texttt{%s}" (match-string 0)) t)))))
+
+;; FIXME - we need better implementation for nested lists
 (defun org-export-latex-fixed-width (opt)
   "When OPT is non-nil convert fixed-width sections to LaTeX."
   (goto-char (point-min))
@@ -731,12 +772,13 @@
 				      (match-string 2)) t t)
 	       (forward-line))))))
 
+;; FIXME Use org-export-highlight-first-table-line ?
 (defun org-export-latex-tables (opt)
   "When OPT is non-nil convert tables to LaTeX."
   (goto-char (point-min))
   (while (re-search-forward "^\\([ \t]*\\)|" nil t)
     ;; Re-align the table to update org-table-last-alignment
-    (save-excursion (save-match-data (org-table-align)))
+    (save-window-excursion (save-match-data (org-table-align)))
     (let (tbl-list
 	  (beg (match-beginning 0))
 	  (end (save-excursion
@@ -749,21 +791,11 @@
 	    (push (split-string (org-trim (match-string 1)) "|") tbl-list)
 	  (push 'hline tbl-list))
 	(forward-line))
-      ;; comment region out instead of deleting it ?
+	;; comment region out instead of deleting it ?
       (apply 'delete-region (list beg end))
       (when opt (insert (orgtbl-to-latex (nreverse tbl-list) 
 					 nil) "\n\n")))))
 
-(defun org-export-latex-special-keywords ()
-  "Convert special keywords to LaTeX.
-Regexps are those from `org-latex-special-string-regexps'."
-  (let ((rg org-latex-special-string-regexps) r)
-    (while (setq r (pop rg))
-      (goto-char (point-min))
-      (while (re-search-forward (eval r) nil t)
-	(replace-match (format "\\\\texttt{%s}" (match-string 0)) t)))))
-
-;; FIXME - we need better implementation for nested lists
 (defun org-export-latex-list (srch0 srch1 srch2 rpl0 rpl1)
   "Convert lists to LaTeX."
   (goto-char (point-min))
@@ -829,17 +861,6 @@
 	       (match-string 5)) t t)
       (backward-char))))
 
-(defun org-export-latex-protect-char-in-string (char-list string)
-  "Add org-protected text-property to char from CHAR-LIST in STRING."
-  (with-temp-buffer
-    (save-match-data
-      (insert string)
-      (goto-char (point-min))
-      (while (re-search-forward (regexp-opt char-list) nil t)
-	(add-text-properties (match-beginning 0)
-			     (match-end 0) '(org-protected t)))
-      (buffer-string))))
-
 (defun org-export-latex-links ()
   ;; Make sure to use the LaTeX hyperref and graphicx package
   ;; or send some warnings.
@@ -888,6 +909,7 @@
 	     (t (insert "\\texttt{" desc "}")))))))
 
 
+;;; org-latex-cleaned-string-for-export:
 (defun org-latex-cleaned-string-for-export (string &rest parameters)
   "Cleanup a buffer STRING so that links can be created safely."
   (interactive)
@@ -988,17 +1010,6 @@
 	    (add-text-properties (point) (org-end-of-subtree t)
 				 '(org-protected t)))))
 
-      ;; Remove or replace comments
-      ;; If :comments is set, use this char for commenting out comments and
-      ;; protect them. otherwise delete them
-      (goto-char (point-min))
-      (while (re-search-forward "^#\\(.*\n?\\)" nil t)
-	(if commentsp
-	    (progn (add-text-properties
-		    (match-beginning 0) (match-end 0) '(org-protected t))
-		   (replace-match (format commentsp (match-string 1)) t t))
-	  (replace-match "")))
-
       ;; Find matches for radio targets and turn them into internal links
       (goto-char (point-min))
       (when re-radio
@@ -1031,7 +1042,7 @@
 	 (let* ((s (concat (match-string 1) "[[" (match-string 2)
 			   ":" (match-string 3) "]]")))
 	   ;; added 'org-protected property to links
-	   (add-text-properties 0 (length s) '(org-protected t) s)
+	   (put-text-property 0 (length s) 'face 'org-link s)
 	   (replace-match s t t))))
       (goto-char (point-min))
       (while (re-search-forward re-angle-link nil t)
@@ -1039,7 +1050,7 @@
 	(org-if-unprotected
 	 (let* ((s (concat (match-string 1) "[[" (match-string 2)
 			   ":" (match-string 3) "]]")))
-	   (add-text-properties 0 (length s) '(org-protected t) s)
+	   (put-text-property 0 (length s) 'face 'org-link s)
 	   (replace-match s t t))))
       (goto-char (point-min))
       (while (re-search-forward org-bracket-link-regexp nil t)
@@ -1051,7 +1062,7 @@
 			       (match-string 2)
 			     (concat "[" xx "]"))
 			   "]")))
-	   (add-text-properties 0 (length s) '(org-protected t) s)
+	   (put-text-property 0 (length s) 'face 'org-link s)
 	   (replace-match s t t))))
 
       ;; Find multiline emphasis and put them into single line
@@ -1070,27 +1081,23 @@
     (kill-buffer " org-mode-tmp")
     rtn))
 
-(defsubst org-latex-protect (string)
-  (add-text-properties 0 (length string) '(org-protected t) string)
-  string)
-
 (defun org-export-latex-cleaned-string ()
   "Clean stuff in the LaTeX export."
 
-  ;; preserve line breaks
+  ;; Preserve line breaks
   (goto-char (point-min))
   (while (re-search-forward "\\\\\\\\" nil t)
     (add-text-properties (match-beginning 0) (match-end 0)
 			 '(org-protected t)))
 
-  ;; convert LaTeX to @LaTeX{}
+  ;; Convert LaTeX to @LaTeX{}
   (goto-char (point-min))
   (let ((case-fold-search nil) rpl)
     (while (re-search-forward "\\([^+_]\\)LaTeX" nil t)
     (replace-match (org-latex-protect 
 		    (concat (match-string 1) "\\LaTeX{}")) t t)))
 
-  ;; convert horizontal rules
+  ;; Convert horizontal rules
   (goto-char (point-min))
   (while (re-search-forward "^----+.$" nil t)
     (replace-match (org-latex-protect "\\hrule") t t))
@@ -1103,10 +1110,10 @@
 	  nil t)
     (beginning-of-line)
     (org-cut-subtree))
-  
-  ;; protect LaTeX \commands{...}
+
+  ;; Protect LaTeX \commands{...}
   (goto-char (point-min))
-  (while (re-search-forward "\\\\[a-z]+{.+}" nil t)
+  (while (re-search-forward "\\\\[a-zA-Z]+\\(?:\\[.*\\]\\)?{.*}" nil t)
     (add-text-properties (match-beginning 0) (match-end 0)
 			 '(org-protected t)))
   
@@ -1117,21 +1124,69 @@
       (replace-match 
        (org-latex-protect (format "\\label{%s}" (match-string 1))) t t)))
   
-  ;; delete @<br /> cookies
+  ;; Delete @<...> constructs
   (goto-char (point-min))
-  (while (re-search-forward "@<[^<>\n]*>" nil t)
+  ;; Thanks to Daniel Clemente for this regexp
+  (while (re-search-forward "@<\\(?:[^\"\n]\\|\".*\"\\)*?>" nil t)
     (replace-match ""))
   
-  ;; add #+BEGIN_LaTeX before any \begin{...}
+  ;; Add #+BEGIN_LaTeX before any \begin{...}
   (goto-char (point-min))
   (while (re-search-forward "^ *\\\\begin{" nil t)
     (replace-match "#+BEGIN_LaTeX:\n\\&" t))
   
-  ;; add #+END_LaTeX after any \end{...}
+  ;; Add #+END_LaTeX after any \end{...}
   (goto-char (point-min))
   (while (re-search-forward "^ *\\\\end{.+}.*$" nil t)
     (replace-match "\\&\n#+END_LaTeX" t))
   
+  ;; Protect stuff from LaTeX processing. 
+  ;; We will get rid on this once org.el integrate org-export-latex.el
+  (goto-char (point-min))
+  (let ((formatters `((,latexp "LaTeX" "BEGIN_LaTeX" "END_LaTeX"))) fmt)
+    (while (re-search-forward "^[ \t]*:.*\\(\n[ \t]*:.*\\)*" nil t)
+      (add-text-properties (match-beginning 0) (match-end 0)
+			   '(org-protected t)))
+    (while formatters
+      (setq fmt (pop formatters))
+      (when (car fmt)
+	(goto-char (point-min))
+	(while (re-search-forward (concat "^#\\+" (cadr fmt) 
+					  ;; ":[ \t]*\\(.*\\)") nil t)
+					  ;; FIXME: authorize spaces after #+LaTeX: 
+					  ;; to get list correctly exported
+					  ":\\(.*\\)") nil t)
+	  (replace-match "\\1" t)
+	  (add-text-properties
+	   (point-at-bol) (min (1+ (point-at-eol)) (point-max))
+	   '(org-protected t))))
+      (goto-char (point-min))
+      (while (re-search-forward
+	      (concat "^#\\+" 
+		      (caddr fmt) "\\>.*\\(\\(\n.*\\)*?\n\\)#\\+"
+		      (cadddr fmt) "\\>.*\n?") nil t)
+	(if (car fmt)
+	    (add-text-properties (match-beginning 1) (1+ (match-end 1))
+				 '(org-protected t))
+	  (delete-region (match-beginning 0) (match-end 0))))
+      (goto-char (point-min))
+      (while (re-search-forward re-quote nil t)
+	(goto-char (match-beginning 0))
+	(end-of-line 1)
+	(add-text-properties (point) (org-end-of-subtree t)
+			     '(org-protected t)))))
+
+  ;; Remove or replace comments
+  ;; If :comments is set, use this char for commenting out comments and
+  ;; protect them. otherwise delete them
+  (goto-char (point-min))
+  (while (re-search-forward "^#\\(.*\n?\\)" nil t)
+    (if commentsp
+	(progn (add-text-properties
+		(match-beginning 0) (match-end 0) '(org-protected t))
+	       (replace-match (format commentsp (match-string 1)) t t))
+      (replace-match "")))
+  
   ;; When converting to LaTeX, replace footnotes
   ;; FIXME: don't protect footnotes from conversion
   (when (plist-get org-latex-options-plist :footnotes)
@@ -1149,18 +1204,18 @@
 	    (let ((end (save-excursion
 			 (if (re-search-forward "^$\\|\\[[0-9]+\\]" nil t)
 			     (match-beginning 0) (point-max)))))
-	      (setq footnote (concat 
-			      (org-trim (buffer-substring (point) end)) 
-			      ;; FIXME stupid workaround for cases where 
-			      ;; `org-bracket-link-analytic-regexp' matches
-			      ;; }. as part of the link.
-			      " "))
+	      (setq footnote
+		    (concat 
+		     (org-trim (buffer-substring (point) end)) 
+		     ;; FIXME stupid workaround for cases where
+		     ;; `org-bracket-link-analytic-regexp' matches
+		     ;; }. as part of the link.
+		     " "))
 	      (delete-region (point) end)))
 	  (goto-char foot-beg)
 	  (delete-region foot-beg foot-end)
 	  (setq footnote-rpl (format "\\footnote{%s}" footnote))
-	  (add-text-properties 0 1 '(org-protected t) footnote-rpl)
-	  (add-text-properties 9 10 '(org-protected t) footnote-rpl)
+	  (add-text-properties 0 10 '(org-protected t) footnote-rpl)
 	  (add-text-properties (1- (length footnote-rpl))
 			       (length footnote-rpl)
 			       '(org-protected t) footnote-rpl)
@@ -1170,43 +1225,8 @@
     (goto-char (point-min))
     (while (re-search-forward 
 	    (concat "^" footnote-section-tag-regexp) nil t)
-      (replace-match "")))
-  
-  ;; Protect stuff from LaTeX processing. 
-  ;; We will get rid on this once org.el integrate org-export-latex.el
-  ;; FIXME: #+LaTeX should be aware of the preceeding indentation in lists
-  (goto-char (point-min))
-  (let ((formatters `((,latexp "LaTeX" "BEGIN_LaTeX" "END_LaTeX"))) fmt)
-    (while (re-search-forward "^[ \t]*:.*\\(\n[ \t]*:.*\\)*" nil t)
-      (add-text-properties (match-beginning 0) (match-end 0)
-			   '(org-protected t)))
-    (while formatters
-      (setq fmt (pop formatters))
-      (when (car fmt)
-	(goto-char (point-min))
-	(while (re-search-forward (concat "^#\\+" (cadr fmt) 
-					  ":[ \t]*\\(.*\\)") nil t)
-	  (replace-match "\\1" t)
-	  (add-text-properties
-	   (point-at-bol) (min (1+ (point-at-eol)) (point-max))
-	   '(org-protected t))))
-      (goto-char (point-min))
-      (while (re-search-forward
-	      (concat "^#\\+" 
-		      (caddr fmt) "\\>.*\\(\\(\n.*\\)*?\n\\)#\\+"
-		      (cadddr fmt) "\\>.*\n?") nil t)
-	(if (car fmt)
-	    (add-text-properties (match-beginning 1) (1+ (match-end 1))
-				 '(org-protected t))
-	  (delete-region (match-beginning 0) (match-end 0))))
-      (goto-char (point-min))
-      (while (re-search-forward re-quote nil t)
-	(goto-char (match-beginning 0))
-	(end-of-line 1)
-	(add-text-properties (point) (org-end-of-subtree t)
-			     '(org-protected t))))))
+      (replace-match ""))))
 
 (provide 'org-export-latex)
 
-;; arch-tag: 23c2b87d-da04-4c2d-ad2d-1eb6487bc3ad
 ;;; org-export-latex.el ends here