diff options
author | Nicolas Goaziou <mail@nicolasgoaziou.fr> | 2016-05-17 23:37:18 +0200 |
---|---|---|
committer | Nicolas Goaziou <mail@nicolasgoaziou.fr> | 2016-05-19 09:44:05 +0200 |
commit | ea1147a479f6df3ffb7ad384a85fc21920e5bafd (patch) | |
tree | e0d9d1bf2b94b0e50e4a8dfbf459578b323e14f5 | |
parent | 14f853dceb5ed14fe8c2d15603d7aa638398aa9e (diff) | |
download | org-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.el | 67 | ||||
-rw-r--r-- | lisp/ox-latex.el | 128 | ||||
-rw-r--r-- | lisp/ox-man.el | 76 | ||||
-rw-r--r-- | lisp/ox-texinfo.el | 106 |
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) |