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
This commit is contained in:
Nicolas Goaziou 2012-01-05 16:01:34 +01:00
parent 3ada986ba3
commit 116dfdd2d5
1 changed files with 156 additions and 0 deletions

View File

@ -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