Explorar o código

EXPERIMENTAL/org-e-latex: Provide a canonical way to compile a .tex file

* EXPERIMENTAL/org-e-latex.el (org-e-latex-pdf-process,
(org-e-latex-logfiles-extensions, org-e-latex-remove-logfiles): New
variables.
(org-e-latex-compile, org-e-latex-collect-errors): New functions
Nicolas Goaziou %!s(int64=13) %!d(string=hai) anos
pai
achega
116dfdd2d5
Modificáronse 1 ficheiros con 156 adicións e 0 borrados
  1. 156 0
      EXPERIMENTAL/org-e-latex.el

+ 156 - 0
EXPERIMENTAL/org-e-latex.el

@@ -573,6 +573,70 @@ string defines the replacement string for this quote."
 		(string :tag "Replacement quote     "))))
 
 
+;;;; Compilation
+
+(defcustom org-e-latex-pdf-process
+  '("pdflatex -interaction nonstopmode -output-directory %o %f"
+    "pdflatex -interaction nonstopmode -output-directory %o %f"
+    "pdflatex -interaction nonstopmode -output-directory %o %f")
+  "Commands to process a LaTeX file to a PDF file.
+This is a list of strings, each of them will be given to the shell
+as a command.  %f in the command will be replaced by the full file name, %b
+by the file base name (i.e. without extension) and %o by the base directory
+of the file.
+
+The reason why this is a list is that it usually takes several runs of
+`pdflatex', maybe mixed with a call to `bibtex'.  Org does not have a clever
+mechanism to detect which of these commands have to be run to get to a stable
+result, and it also does not do any error checking.
+
+By default, Org uses 3 runs of `pdflatex' to do the processing.  If you
+have texi2dvi on your system and if that does not cause the infamous
+egrep/locale bug:
+
+     http://lists.gnu.org/archive/html/bug-texinfo/2010-03/msg00031.html
+
+then `texi2dvi' is the superior choice.  Org does offer it as one
+of the customize options.
+
+Alternatively, this may be a Lisp function that does the processing, so you
+could use this to apply the machinery of AUCTeX or the Emacs LaTeX mode.
+This function should accept the file name as its single argument."
+  :group 'org-export-pdf
+  :type '(choice
+	  (repeat :tag "Shell command sequence"
+		  (string :tag "Shell command"))
+	  (const :tag "2 runs of pdflatex"
+		 ("pdflatex -interaction nonstopmode -output-directory %o %f"
+		   "pdflatex -interaction nonstopmode -output-directory %o %f"))
+	  (const :tag "3 runs of pdflatex"
+		 ("pdflatex -interaction nonstopmode -output-directory %o %f"
+		   "pdflatex -interaction nonstopmode -output-directory %o %f"
+		   "pdflatex -interaction nonstopmode -output-directory %o %f"))
+	  (const :tag "pdflatex,bibtex,pdflatex,pdflatex"
+		 ("pdflatex -interaction nonstopmode -output-directory %o %f"
+		   "bibtex %b"
+		   "pdflatex -interaction nonstopmode -output-directory %o %f"
+		   "pdflatex -interaction nonstopmode -output-directory %o %f"))
+	  (const :tag "texi2dvi"
+		 ("texi2dvi -p -b -c -V %f"))
+	  (const :tag "rubber"
+		 ("rubber -d --into %o %f"))
+	  (function)))
+
+(defcustom org-e-latex-logfiles-extensions
+  '("aux" "idx" "log" "out" "toc" "nav" "snm" "vrb")
+  "The list of file extensions to consider as LaTeX logfiles."
+  :group 'org-export-e-latex
+  :type '(repeat (string :tag "Extension")))
+
+(defcustom org-e-latex-remove-logfiles t
+  "Non-nil means remove the logfiles produced by PDF production.
+These are the .aux, .log, .out, and .toc files."
+  :group 'org-export-e-latex
+  :type 'boolean)
+
+
 
 ;;; Internal Functions
 
@@ -1839,5 +1903,97 @@ CONTENTS is nil. INFO is a plist holding contextual information."
      (format "\\begin{verse}\n%s\\end{verse}" contents))))
 
 
+
+;;; Compilation
+
+(defun org-e-latex-compile (texfile)
+  "Compile a TeX file.
+
+TEXFILE is the name of the file being compiled.  Processing is
+done through the command specified in `org-e-latex-pdf-process'.
+
+Return PDF file name or an error if it couldn't be produced."
+  (let* ((wconfig (current-window-configuration))
+	 (texfile (file-truename texfile))
+	 (base (file-name-sans-extension texfile))
+	 errors)
+    (message (format "Processing LaTeX file " texfile "..." texfile))
+    (unwind-protect
+	(progn
+	  (cond
+	   ;; A function is provided: Apply it.
+	   ((functionp org-latex-to-pdf-process)
+	    (funcall org-latex-to-pdf-process (shell-quote-argument texfile)))
+	   ;; A list is provided: Replace %b, %f and %o with appropriate
+	   ;; values in each command before applying it.  Output is
+	   ;; redirected to "*Org PDF LaTeX Output*" buffer.
+	   ((consp org-e-latex-pdf-process)
+	    (let* ((out-dir (or (file-name-directory texfile) "./"))
+		   (outbuf (get-buffer-create "*Org PDF LaTeX Output*")))
+	      (mapc
+	       (lambda (command)
+		 (shell-command
+		  (replace-regexp-in-string
+		   "%b" (shell-quote-argument base)
+		   (replace-regexp-in-string
+		    "%f" (shell-quote-argument texfile)
+		    (replace-regexp-in-string
+		     "%o" (shell-quote-argument out-dir) command)))
+		  outbuf))
+	       org-e-latex-pdf-process)
+	      ;; Collect standard errors from output buffer.
+	      (setq errors (org-e-latex-collect-errors outbuf))))
+	   (t (error "No valid command to process to PDF")))
+	  (let ((pdffile (concat base ".pdf")))
+	    ;; Check for process failure.  Provide collected errors if
+	    ;; possible.
+	    (if (not (file-exists-p pdffile))
+		(error (concat (format "PDF file %s wasn't produced" pdffile)
+			       (when errors (concat ": " errors))))
+	      ;; Else remove log files, when specified, and signal end of
+	      ;; process to user, along with any error encountered.
+	      (when org-e-latex-remove-logfiles
+		(dolist (ext org-e-latex-logfiles-extensions)
+		  (let ((file (concat base "." ext)))
+		    (when (file-exists-p file) (delete-file file)))))
+	      (message (concat "Process completed"
+			       (if (not errors) "."
+				 (concat " with errors: " errors)))))
+	    ;; Return output file name.
+	    pdffile))
+      (set-window-configuration wconfig))))
+
+(defun org-e-latex-collect-errors (buffer)
+  "Collect some kind of errors from \"pdflatex\" command output.
+
+BUFFER is the buffer containing output.
+
+Return collected error types as a string, or nil if there was
+none."
+  (with-current-buffer buffer
+    (save-excursion
+      (goto-char (point-max))
+      ;; Find final "pdflatex" run.
+      (when (re-search-backward "^[ \t]*This is pdf.*?TeX.*?Version" nil t)
+	(let ((case-fold-search t)
+	      (errors ""))
+	  (when (save-excursion
+		  (re-search-forward "Reference.*?undefined" nil t))
+	    (setq errors (concat errors " [undefined reference]")))
+	  (when (save-excursion
+		  (re-search-forward "Citation.*?undefined" nil t))
+	    (setq errors (concat errors " [undefined citation]")))
+	  (when (save-excursion
+		  (re-search-forward "Undefined control sequence" nil t))
+	    (setq errors (concat errors " [undefined control sequence]")))
+	  (when (save-excursion
+		  (re-search-forward "^! LaTeX.*?Error"))
+	    (setq errors (concat errors " [LaTeX error]")))
+	  (when (save-excursion
+		  (re-search-forward "^! Package.*?Error"))
+	    (setq errors (concat errors " [package error]")))
+	  (and (org-string-nw-p errors) (org-trim errors)))))))
+
+
 (provide 'org-e-latex)
 ;;; org-e-latex.el ends here