summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Goaziou <mail@nicolasgoaziou.fr>2016-05-17 23:37:18 +0200
committerNicolas Goaziou <mail@nicolasgoaziou.fr>2016-05-19 09:44:05 +0200
commitea1147a479f6df3ffb7ad384a85fc21920e5bafd (patch)
treee0d9d1bf2b94b0e50e4a8dfbf459578b323e14f5
parent14f853dceb5ed14fe8c2d15603d7aa638398aa9e (diff)
downloadorg-mode-ea1147a479f6df3ffb7ad384a85fc21920e5bafd.tar.gz
Add `org-compile-file' and `org-file-newer-than-p'
* lisp/org.el (org-compile-file): (org-file-newer-than-p): New functions. * lisp/ox-latex.el (org-latex-compile): Use new functions. * lisp/ox-man.el (org-man-compile): Use new functions. (org-man-collect-errors): Remove it. * lisp/ox-texinfo.el (org-texinfo-compile): Use new functions. (org-texinfo-collect-errors): Remove function as it is not accurate enough (e.g., it doesn't handle internationalization).
-rw-r--r--lisp/org.el67
-rw-r--r--lisp/ox-latex.el128
-rw-r--r--lisp/ox-man.el76
-rw-r--r--lisp/ox-texinfo.el106
4 files changed, 144 insertions, 233 deletions
diff --git a/lisp/org.el b/lisp/org.el
index c667eab..93d66ad 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -22852,6 +22852,73 @@ hierarchy of headlines by UP levels before marking the subtree."
(call-interactively 'org-mark-element)
(org-mark-element)))
+(defun org-file-newer-than-p (file time)
+ "Non-nil if FILE is newer than TIME.
+FILE is a filename, as a string, TIME is a list of integers, as
+returned by, e.g., `current-time'."
+ (and (file-exists-p file)
+ ;; Only compare times up to whole seconds as some file-systems
+ ;; (e.g. HFS+) do not retain any finer granularity. As
+ ;; a consequence, make sure we return non-nil when the two
+ ;; times are equal.
+ (not (time-less-p (cl-subseq (nth 5 (file-attributes file)) 0 2)
+ (cl-subseq time 0 2)))))
+
+(defun org-compile-file (source process ext &optional err-msg log-buf spec)
+ "Compile a SOURCE file using PROCESS.
+
+PROCESS is either a function or a list of shell commands, as
+strings. EXT is a file extension, without the leading dot, as
+a string. It is used to check if the process actually succeeded.
+
+PROCESS must create a file with the same base name and directory
+as SOURCE, but ending with EXT. The function then returns its
+filename. Otherwise, it raises an error. The error message can
+then be refined by providing string ERR-MSG, which is appended to
+the standard message.
+
+If PROCESS is a function, it is called with a single argument:
+the SOURCE file.
+
+If it is a list of commands, each of them is called using
+`shell-command'. By default, in each command, %b, %f and %o are
+replaced, respectively, with SOURCE base name, SOURCE full name
+and SOURCE directory. It is possible, however, to use more
+place-holders by specifying them in optional argument SPEC, as an
+alist following the pattern (CHARACTER . REPLACEMENT-STRING).
+
+When PROCESS is a list of commands, optional argument LOG-BUF can
+be set to a buffer or a buffer name. `shell-command' then uses
+it for output.
+
+`default-directory' is set to SOURCE directory during the whole
+process."
+ (let* ((base-name (file-name-sans-extension (file-name-nondirectory source)))
+ (full-name (file-truename source))
+ (out-dir (file-name-directory source))
+ ;; Properly set working directory for compilation.
+ (default-directory (if (file-name-absolute-p source)
+ (file-name-directory full-name)
+ default-directory))
+ (time (current-time))
+ (err-msg (if (stringp err-msg) (concat ". " err-msg) "")))
+ (save-window-excursion
+ (pcase process
+ ((pred functionp) (funcall process (shell-quote-argument source)))
+ ((pred consp)
+ (let ((log-buf (and log-buf (get-buffer-create log-buf)))
+ (spec (append spec
+ `((?b . ,(shell-quote-argument base-name))
+ (?f . ,(shell-quote-argument full-name))
+ (?o . ,(shell-quote-argument out-dir))))))
+ (dolist (command process)
+ (shell-command (format-spec command spec) log-buf))))
+ (_ (error "No valid command to process %S%s" source err-msg)))
+ ;; Check for process failure.
+ (let ((output (concat out-dir base-name "." ext)))
+ (unless (org-file-newer-than-p output time)
+ (error (format "File %S wasn't produced%s" output err-msg)))
+ output))))
;;; Indentation
diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el
index 7fa68c5..9c31645 100644
--- a/lisp/ox-latex.el
+++ b/lisp/ox-latex.el
@@ -3519,87 +3519,59 @@ Return PDF file's name."
"Compile a TeX file.
TEXFILE is the name of the file being compiled. Processing is
-done through the command specified in `org-latex-pdf-process'.
+done through the command specified in `org-latex-pdf-process',
+which see. Output is redirected to \"*Org PDF LaTeX Output*\"
+buffer.
When optional argument SNIPPET is non-nil, TEXFILE is a temporary
file used to preview a LaTeX snippet. In this case, do not
-create a log buffer and do not bother removing log files.
-
-Return PDF file name or an error if it couldn't be produced."
- (let* ((base-name (file-name-sans-extension (file-name-nondirectory texfile)))
- (full-name (file-truename texfile))
- (compiler (or (with-temp-buffer
- (save-excursion (insert-file-contents full-name))
- (when (and (search-forward-regexp
- (regexp-opt org-latex-compilers) (line-end-position 2) t)
- (progn (beginning-of-line)
- (looking-at-p "%")))
- (match-string 0)))
- "pdflatex"))
- (out-dir (file-name-directory texfile))
- ;; Properly set working directory for compilation.
- (default-directory (if (file-name-absolute-p texfile)
- (file-name-directory full-name)
- default-directory))
- (time (current-time))
- warnings)
- (unless snippet (message "Processing LaTeX file %s..." texfile))
- (save-window-excursion
- (cond
- ;; A function is provided: Apply it.
- ((functionp org-latex-pdf-process)
- (funcall org-latex-pdf-process (shell-quote-argument texfile)))
- ;; A list is provided: Replace %b, %f and %o with appropriate
- ;; values in each command before applying it. Note that while
- ;; "%latex" and "%bibtex" is used in `org-latex-pdf-process',
- ;; they are replaced with "%L" and "%B" to adhere to
- ;; format-spec. Output is redirected to "*Org PDF LaTeX
- ;; Output*" buffer.
- ((consp org-latex-pdf-process)
- (let ((outbuf (and (not snippet)
- (get-buffer-create "*Org PDF LaTeX Output*")))
- (spec (list (cons ?B (shell-quote-argument org-latex-bib-compiler))
- (cons ?L (shell-quote-argument compiler))
- (cons ?b (shell-quote-argument base-name))
- (cons ?f (shell-quote-argument full-name))
- (cons ?o (shell-quote-argument out-dir)))))
- (dolist (command org-latex-pdf-process)
- (let ((c (replace-regexp-in-string
- "%\\(latex\\|bibtex\\)\\>"
- (lambda (str) (upcase (substring str 0 2)))
- command)))
- (shell-command (format-spec c spec) outbuf)))
- ;; Collect standard errors from output buffer.
- (setq warnings (and (not snippet)
- (org-latex--collect-warnings outbuf)))))
- (t (error "No valid command to process to PDF")))
- (let ((pdffile (concat out-dir base-name ".pdf")))
- ;; Check for process failure. Provide collected errors if
- ;; possible.
- (if (or (not (file-exists-p pdffile))
- ;; Only compare times up to whole seconds as some filesystems
- ;; (e.g. HFS+) do not retain any finer granularity.
- (time-less-p (cl-subseq (nth 5 (file-attributes pdffile)) 0 2)
- (cl-subseq time 0 2)))
- (error (format "PDF file %s wasn't produced" pdffile))
- ;; Else remove log files, when specified, and signal end of
- ;; process to user, along with any error encountered.
- (unless snippet
- (when org-latex-remove-logfiles
- (dolist (file (directory-files
- out-dir t
- (concat (regexp-quote base-name)
- "\\(?:\\.[0-9]+\\)?"
- "\\."
- (regexp-opt org-latex-logfiles-extensions))))
- (delete-file file)))
- (message (concat "PDF file produced"
- (cond
- ((eq warnings 'error) " with errors.")
- (warnings (concat " with warnings: " warnings))
- (t "."))))))
- ;; Return output file name.
- pdffile))))
+create a log buffer and do not remove log files.
+
+Return PDF file name or raise an error if it couldn't be
+produced."
+ (unless snippet (message "Processing LaTeX file %s..." texfile))
+ (let* ((compiler
+ (or (with-temp-buffer
+ (save-excursion (insert-file-contents texfile))
+ (and (search-forward-regexp (regexp-opt org-latex-compilers)
+ (line-end-position 2)
+ t)
+ (progn (beginning-of-line) (looking-at-p "%"))
+ (match-string 0)))
+ "pdflatex"))
+ (process (if (functionp org-latex-pdf-process) org-latex-pdf-process
+ ;; Replace "%latex" and "%bibtex" with,
+ ;; respectively, "%L" and "%B" so as to adhere to
+ ;; `format-spec' specifications.
+ (mapcar (lambda (command)
+ (replace-regexp-in-string
+ "%\\(?:bib\\|la\\)tex\\>"
+ (lambda (m) (upcase (substring m 0 2)))
+ command))
+ org-latex-pdf-process)))
+ (spec `((?B . ,(shell-quote-argument org-latex-bib-compiler))
+ (?L . ,(shell-quote-argument compiler))))
+ (log-buf-name "*Org PDF LaTeX Output*")
+ (log-buf (and (not snippet) (get-buffer-create log-buf-name)))
+ (outfile (org-compile-file texfile process "pdf"
+ (format "See %S for details" log-buf-name)
+ log-buf spec)))
+ (unless snippet
+ (when org-latex-remove-logfiles
+ (mapc #'delete-file
+ (directory-files
+ (file-name-directory texfile) t
+ (concat (regexp-quote (file-name-base outfile))
+ "\\(?:\\.[0-9]+\\)?\\."
+ (regexp-opt org-latex-logfiles-extensions)))))
+ (let ((warnings (org-latex--collect-warnings log-buf)))
+ (message (concat "PDF file produced"
+ (cond
+ ((eq warnings 'error) " with errors.")
+ (warnings (concat " with warnings: " warnings))
+ (t "."))))))
+ ;; Return output file name.
+ outfile))
(defun org-latex--collect-warnings (buffer)
"Collect some warnings from \"pdflatex\" command output.
diff --git a/lisp/ox-man.el b/lisp/ox-man.el
index 1a646f5..55d50ac 100644
--- a/lisp/ox-man.el
+++ b/lisp/ox-man.el
@@ -1127,73 +1127,15 @@ FILE is the name of the file being compiled. Processing is done
through the command specified in `org-man-pdf-process'.
Return PDF file name or an error if it couldn't be produced."
- (let* ((base-name (file-name-sans-extension (file-name-nondirectory file)))
- (full-name (file-truename file))
- (out-dir (file-name-directory file))
- (time (current-time))
- ;; Properly set working directory for compilation.
- (default-directory (if (file-name-absolute-p file)
- (file-name-directory full-name)
- default-directory))
- errors)
- (message "Processing Groff file %s..." file)
- (save-window-excursion
- (cond
- ;; A function is provided: Apply it.
- ((functionp org-man-pdf-process)
- (funcall org-man-pdf-process (shell-quote-argument file)))
- ;; A list is provided: Replace %b, %f and %o with appropriate
- ;; values in each command before applying it. Output is
- ;; redirected to "*Org PDF Groff Output*" buffer.
- ((consp org-man-pdf-process)
- (let ((outbuf (get-buffer-create "*Org PDF Groff Output*")))
- (dolist (command org-man-pdf-process)
- (shell-command
- (replace-regexp-in-string
- "%b" (shell-quote-argument base-name)
- (replace-regexp-in-string
- "%f" (shell-quote-argument full-name)
- (replace-regexp-in-string
- "%o" (shell-quote-argument out-dir) command t t) t t) t t)
- outbuf))
- ;; Collect standard errors from output buffer.
- (setq errors (org-man-collect-errors outbuf))))
- (t (error "No valid command to process to PDF")))
- (let ((pdffile (concat out-dir base-name ".pdf")))
- ;; Check for process failure. Provide collected errors if
- ;; possible.
- (if (or (not (file-exists-p pdffile))
- ;; Only compare times up to whole seconds as some
- ;; filesystems (e.g. HFS+) do not retain any finer
- ;; granularity.
- (time-less-p (cl-subseq (nth 5 (file-attributes pdffile)) 0 2)
- (cl-subseq time 0 2)))
- (error "PDF file %s wasn't produced%s"
- pdffile
- (if errors (concat ": " errors) ""))
- ;; Else remove log files, when specified, and signal end of
- ;; process to user, along with any error encountered.
- (when org-man-remove-logfiles
- (dolist (ext org-man-logfiles-extensions)
- (let ((file (concat out-dir base-name "." 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))))
-
-(defun org-man-collect-errors (buffer)
- "Collect some kind of errors from \"groff\" 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 run
- nil )))
-
+ (message "Processing Groff file %s..." file)
+ (let ((output (org-compile-file file org-man-pdf-process "pdf")))
+ (when org-man-remove-logfiles
+ (let ((base (file-name-sans-extension output)))
+ (dolist (ext org-man-logfiles-extensions)
+ (let ((file (concat base "." ext)))
+ (when (file-exists-p file) (delete-file file))))))
+ (message "Process completed.")
+ output))
(provide 'ox-man)
diff --git a/lisp/ox-texinfo.el b/lisp/ox-texinfo.el
index 705d9d7..99ba392 100644
--- a/lisp/ox-texinfo.el
+++ b/lisp/ox-texinfo.el
@@ -1563,96 +1563,26 @@ this command to convert it."
(defun org-texinfo-compile (file)
"Compile a texinfo file.
-FILE is the name of the file being compiled. Processing is
-done through the command specified in `org-texinfo-info-process'.
+FILE is the name of the file being compiled. Processing is done
+through the command specified in `org-texinfo-info-process',
+which see. Output is redirected to \"*Org INFO Texinfo Output*\"
+buffer.
Return INFO file name or an error if it couldn't be produced."
- (let* ((base-name (file-name-sans-extension (file-name-nondirectory file)))
- (full-name (file-truename file))
- (out-dir (file-name-directory file))
- (time (current-time))
- ;; Properly set working directory for compilation.
- (default-directory (if (file-name-absolute-p file)
- (file-name-directory full-name)
- default-directory))
- errors)
- (message "Processing Texinfo file %s..." file)
- (save-window-excursion
- ;; Replace %b, %f and %o with appropriate values in each command
- ;; before applying it. Output is redirected to "*Org INFO
- ;; Texinfo Output*" buffer.
- (let ((outbuf (get-buffer-create "*Org INFO Texinfo Output*")))
- (with-current-buffer outbuf (compilation-mode))
- (dolist (command org-texinfo-info-process)
- (shell-command
- (replace-regexp-in-string
- "%b" (shell-quote-argument base-name)
- (replace-regexp-in-string
- "%f" (shell-quote-argument full-name)
- (replace-regexp-in-string
- "%o" (shell-quote-argument out-dir) command t t) t t) t t)
- outbuf))
- ;; Collect standard errors from output buffer.
- (setq errors (org-texinfo-collect-errors outbuf)))
- (let ((infofile (concat out-dir base-name ".info")))
- ;; Check for process failure. Provide collected errors if
- ;; possible.
- (if (or (not (file-exists-p infofile))
- ;; Only compare times up to whole seconds as some
- ;; filesystems (e.g. HFS+) do not retain any finer
- ;; granularity.
- (time-less-p (cl-subseq (nth 5 (file-attributes infofile)) 0 2)
- (cl-subseq time 0 2)))
- (error "INFO file %s wasn't produced%s" infofile
- (if errors (concat ": " errors) ""))
- ;; Else remove log files, when specified, and signal end of
- ;; process to user, along with any error encountered.
- (when org-texinfo-remove-logfiles
- (dolist (ext org-texinfo-logfiles-extensions)
- (let ((file (concat out-dir base-name "." ext)))
- (when (file-exists-p file) (delete-file file)))))
- (message (concat "Process completed"
- (if (not errors) "."
- (concat " with errors: " errors)))))
- ;; Return output file name.
- infofile))))
-
-(defun org-texinfo-collect-errors (buffer)
- "Collect some kind of errors from \"makeinfo\" 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-min))
- ;; Find final "makeinfo" run.
- (when t
- (let ((case-fold-search t)
- (errors ""))
- (when (save-excursion
- (re-search-forward "perhaps incorrect sectioning?" nil t))
- (setq errors (concat errors " [incorrect sectioning]")))
- (when (save-excursion
- (re-search-forward "missing close brace" nil t))
- (setq errors (concat errors " [syntax error]")))
- (when (save-excursion
- (re-search-forward "Unknown command" nil t))
- (setq errors (concat errors " [undefined @command]")))
- (when (save-excursion
- (re-search-forward "No matching @end" nil t))
- (setq errors (concat errors " [block incomplete]")))
- (when (save-excursion
- (re-search-forward "requires a sectioning" nil t))
- (setq errors (concat errors " [invalid section command]")))
- (when (save-excursion
- (re-search-forward "\\[unexpected\ ]" nil t))
- (setq errors (concat errors " [unexpected error]")))
- (when (save-excursion
- (re-search-forward "misplaced " nil t))
- (setq errors (concat errors " [syntax error]")))
- (and (org-string-nw-p errors) (org-trim errors)))))))
+ (message "Processing Texinfo file %s..." file)
+ (let* ((log-name "*Org INFO Texinfo Output*")
+ (log (get-buffer-create log-name))
+ (output
+ (org-compile-file file org-texinfo-info-process "info"
+ (format "See %S for details" log-name)
+ log)))
+ (when org-texinfo-remove-logfiles
+ (let ((base (file-name-sans-extension output)))
+ (dolist (ext org-texinfo-logfiles-extensions)
+ (let ((file (concat base "." ext)))
+ (when (file-exists-p file) (delete-file file))))))
+ (message "Process completed.")
+ output))
(provide 'ox-texinfo)