Hello,
I've had some time to work on this patch (which outputs the tex output files to
a directory). The attached is against the latest commit 6db8a1a373.
I am not sure if there's still interest in incorporating this patch, but I have
been using this setup for quite some time and I am very pleased by it. Uwe
Brauer also helped me debug the patch and found a couple of issues that I fixed.
Currently, I am wondering if I can get some input from the community on some
implementation aspects.
Here are the things I changed:
- The buffer-local variable `TeX-output-dir` which contains the output
directory. This is only relevant in the buffer of the master file.
- The way that the output directory is prepended to an output file in
`TeX-master-file` is by checking if the extension is in the "clean" list that
`TeX-clean` would normally delete.
This required some refactoring of `TeX-clean` and introducing a function
`TeX--clean-extensions-regexp`. I also implemented a function
`TeX-master-output-file` which returns an output file by prepending the
`TeX-output-dir` (if non-nil).
- I defined several expansion macros including
-- `%(output-dir)"` which expands to `--output-directory=DIR` and is used
for TeX and Biber
-- `%(O?aux)` returning the aux output file, used for `makeglossaries`.
-- `%(O?idx)` returning the idx output file, used for `makeindex`.
-- `%(O?pdf)` returning a pdf output file, used for `Ps2pdf` and `Dvipdfmx`.
- I changed the command list to use the previously defined macros.
- The output files of region are not moved into the output directory. It is not
clear to me what the correct behaviour here would be. My opinion is that
`TeX-region` should control both the place of `_region_.tex` and its output
files. This is not currently supported in AUCTeX but is implemented in this
patch through the `%(output-dir)` expansion.
Here are the points I am unsure of:
- In tex-buf.el, there are several calls which append outputs extensions
("(TeX-output-extension)", ".ind", ".idx" and ".bbl") to an argument `name` or
similar to get a filename. These should be changed to use TeX-active-master or
similar instead but I am unsure of the implications or how to do this without
breaking previous behaviour.
- There is the question of creating the output directory if it doesn't exists.
Some commands (including TeX) assume that the directory exists. Currently I am
creating the directory in `TeX-run-TeX` by calling `TeX--ensure-output-dir`.
- There are several commands that might need changing to account for the
output-directory (or could use it). I don't use these tools nor know their
particularities, so I am hoping someone who does can give me guidance. These
include
-- Makeinfo
-- AmSTeX
-- ConTeXt
-- upmendex
- Known issue: The directory in `TeX-output-dir` cannot be hidden (or start
with `.`). This is a limitation by the tex suite for security reasons.
Any input on this is welcome. I would be happy if this is to be included in
AUCTeX (I already signed the FSF agreement).
Best regards,
-- Al
diff --git a/tex-buf.el b/tex-buf.el
index 40a2acca..9a8769a5 100644
--- a/tex-buf.el
+++ b/tex-buf.el
@@ -1138,6 +1138,10 @@ run of `TeX-run-TeX', use
;; Presence of error is reported inside `TeX-TeX-sentinel-check'
(let ((current-master (TeX-master-file))
(idx-file nil) (element nil))
+
+ ;; Ensure that the output directory exists
+ (TeX--ensure-output-dir)
+
;; the current master file is saved because error routines are
;; parsed in other buffers;
(setq TeX-error-report-switches
diff --git a/tex.el b/tex.el
index b59aee05..b2ab06bb 100644
--- a/tex.el
+++ b/tex.el
@@ -182,7 +182,7 @@ If nil, none is specified."
;; `TeX-expand-list-builtin' for a description of the % escapes
(defcustom TeX-command-list
- '(("TeX" "%(PDF)%(tex) %(file-line-error) %`%(extraopts) %S%(PDFout)%(mode)%' %t"
+ '(("TeX" "%(PDF)%(tex) %(file-line-error) %`%(extraopts) %(output-dir) %S%(PDFout)%(mode)%' %t"
TeX-run-TeX nil
(plain-tex-mode ams-tex-mode texinfo-mode) :help "Run plain TeX")
("LaTeX" "%`%l%(mode)%' %T"
@@ -202,11 +202,11 @@ If nil, none is specified."
("ConTeXt Full" "%(cntxcom) %(extraopts) %(execopts)%t"
TeX-run-TeX nil
(context-mode) :help "Run ConTeXt until completion")
- ("BibTeX" "bibtex %s" TeX-run-BibTeX nil
+ ("BibTeX" "bibtex %(O?aux)" TeX-run-BibTeX nil
(plain-tex-mode latex-mode doctex-mode ams-tex-mode texinfo-mode
context-mode)
:help "Run BibTeX")
- ("Biber" "biber %s" TeX-run-Biber nil
+ ("Biber" "biber %s %(output-dir)" TeX-run-Biber nil
(plain-tex-mode latex-mode doctex-mode ams-tex-mode texinfo-mode)
:help "Run Biber")
("View" "%V" TeX-run-discard-or-function t t :help "Run Viewer")
@@ -219,17 +219,17 @@ If nil, none is specified."
("Dvips" "%(o?)dvips %d -o %f " TeX-run-dvips nil
(plain-tex-mode latex-mode doctex-mode ams-tex-mode texinfo-mode)
:help "Convert DVI file to PostScript")
- ("Dvipdfmx" "dvipdfmx %d" TeX-run-dvipdfmx nil
+ ("Dvipdfmx" "dvipdfmx %d -o %(O?pdf)" TeX-run-dvipdfmx nil
(plain-tex-mode latex-mode doctex-mode ams-tex-mode texinfo-mode)
:help "Convert DVI file to PDF with dvipdfmx")
- ("Ps2pdf" "ps2pdf %f" TeX-run-ps2pdf nil
+ ("Ps2pdf" "ps2pdf %f %(O?pdf)" TeX-run-ps2pdf nil
(plain-tex-mode latex-mode doctex-mode ams-tex-mode texinfo-mode)
:help "Convert PostScript file to PDF")
- ("Glossaries" "makeglossaries %s" TeX-run-command nil
+ ("Glossaries" "makeglossaries %(O?aux)" TeX-run-command nil
(plain-tex-mode latex-mode doctex-mode ams-tex-mode texinfo-mode)
:help "Run makeglossaries to create glossary
file")
- ("Index" "makeindex %s" TeX-run-index nil
+ ("Index" "makeindex %(O?idx)" TeX-run-index nil
(plain-tex-mode latex-mode doctex-mode ams-tex-mode texinfo-mode)
:help "Run makeindex to create index file")
("upMendex" "upmendex %s" TeX-run-index t
@@ -393,7 +393,7 @@ The executable `latex' is LaTeX version 2e."
(defcustom LaTeX-command-style
;; They have all been combined in LaTeX 2e.
- '(("" "%(PDF)%(latex) %(file-line-error) %(extraopts) %S%(PDFout)"))
+ '(("" "%(PDF)%(latex) %(file-line-error) %(extraopts) %(output-dir) %S%(PDFout)"))
"List of style options and LaTeX commands.
If the first element (a regular expression) matches the name of one of
@@ -563,6 +563,11 @@ string."
("%(cntxcom)" ConTeXt-expand-command)
("%(execopts)" ConTeXt-expand-options)
("%(extraopts)" (lambda () TeX-command-extra-options))
+ ("%(output-dir)" (lambda () (if-let ((out-dir (if TeX-current-process-region-p
+ (file-name-directory TeX-region)
+ (TeX-output-dir))))
+ (concat "--output-directory=\"" out-dir "\"")
+ "")))
("%S" TeX-source-correlate-expand-options)
("%dS" TeX-source-specials-view-expand-options)
("%cS" TeX-source-specials-view-expand-client)
@@ -632,6 +637,9 @@ string."
("%n" TeX-current-line)
("%d" TeX-active-master-with-quotes "dvi" t)
("%f" TeX-active-master-with-quotes "ps" t)
+ ("%(O?aux)" TeX-active-master-with-quotes "aux" t)
+ ("%(O?idx)" TeX-active-master-with-quotes "idx" t)
+ ("%(O?pdf)" TeX-active-master-with-quotes "pdf" t)
("%o" (lambda nil (TeX-active-master-with-quotes (TeX-output-extension) t)))
;; for source specials the file name generated for the xdvi
;; command needs to be relative to the master file, just in
@@ -2210,26 +2218,20 @@ Used as a default in TeX, LaTeX and docTeX mode.")
If prefix ARG is non-nil, not only remove intermediate but also
output files."
(interactive "P")
- (let* ((mode-prefix (TeX-mode-prefix))
- (suffixes (append (symbol-value
- (intern (concat mode-prefix
- "-clean-intermediate-suffixes")))
- (when arg
- (symbol-value
- (intern (concat mode-prefix
- "-clean-output-suffixes"))))))
- (master (TeX-active-master))
- (master-dir (file-name-directory master))
- (regexp (concat "\\("
- (regexp-quote (file-name-nondirectory master)) "\\|"
- (regexp-quote (TeX-region-file nil t))
- "\\)"
- "\\("
- (mapconcat 'identity suffixes "\\|")
- "\\)\\'"
- "\\|" (regexp-quote (TeX-region-file t t))))
- (files (when regexp
- (directory-files (or master-dir ".") nil regexp))))
+ (let* (;; Add output extension then remove it, to make sure we get the correct
+ ;; directory in cases TeX-output-dir is non-nil
+ (master (file-name-sans-extension (TeX-active-master (TeX-output-extension))))
+ (master-dir (file-name-directory master))
+ (regexp (concat "\\("
+ (regexp-quote (file-name-nondirectory master)) "\\|"
+ (regexp-quote (TeX-region-file nil t))
+ "\\)"
+ "\\("
+ (TeX--clean-extensions-regexp arg)
+ "\\)\\'"
+ "\\|" (regexp-quote (TeX-region-file t t))))
+ (files (when (and regexp (or (not master-dir) (file-exists-p master-dir)))
+ (directory-files (or master-dir ".") nil regexp))))
(if files
(when (or (not TeX-clean-confirm)
(dired-mark-pop-up " *Deletions*" 'delete
@@ -2241,6 +2243,19 @@ output files."
(delete-file (concat master-dir file))))
(message "No files to be deleted"))))
+(defun TeX--clean-extensions-regexp (&optional arg)
+ "Returns a regexp to match extensions that should be cleaned by TeX-clean.
+If the optional argument ARG is non-nil then output files are included"
+ (when-let ((mode-prefix (TeX-mode-prefix))
+ (suffixes (append (symbol-value
+ (intern (concat mode-prefix
+ "-clean-intermediate-suffixes")))
+ (when arg
+ (symbol-value
+ (intern (concat mode-prefix
+ "-clean-output-suffixes")))))))
+ (mapconcat 'identity suffixes "\\|")))
+
;;; Master File
(defcustom TeX-master t
@@ -2334,6 +2349,25 @@ this variable to \"<none>\"."
'path))
(TeX-add-local-master))))))
+(defun TeX-master-output-file (&optional extension)
+ "Returns an output file based on `TeX-output-dir' in the
+master-file, opening it if necessary. if the optional argument
+EXTENSION is non-nil it is appended as an extension to the output
+file. If EXTENSION is t then (TeX-output-extension) is used."
+ (interactive)
+ (if (eq extension t)
+ (setq extension (TeX-output-extension)))
+ (let ((file (TeX-master-file t)) name)
+ (with-current-buffer
+ (or (find-buffer-visiting file)
+ (find-file-noselect file))
+ (when TeX-output-dir
+ (setq name (concat TeX-output-dir "/" (TeX-master-file)))))
+ (if name
+ (if extension (concat name "." extension)
+ name)
+ (TeX-master-file extension))))
+
(defun TeX-master-file (&optional extension nondirectory ask)
"Set and return the name of the master file for the current document.
@@ -2394,9 +2428,13 @@ name of master file if it cannot be determined otherwise."
;; Ask the user (but add it as a local variable).
(ask (TeX-master-file-ask)))))
- (let ((name (if (stringp TeX-master)
- TeX-master
- my-name)))
+ (if (and TeX-output-dir
+ (when-let (reg (TeX--clean-extensions-regexp t))
+ (string-match-p reg (concat "." extension))))
+ (TeX-master-output-file extension)
+ (let ((name (if (stringp TeX-master)
+ TeX-master
+ my-name)))
(if (TeX-match-extension name)
;; If it already has an extension...
@@ -2411,8 +2449,8 @@ name of master file if it cannot be determined otherwise."
(setq name (file-name-nondirectory name)))
(if extension
- (concat name "." extension)
- name))))
+ (concat name "." extension)
+ name)))))
(defun TeX-master-directory ()
"Directory of master file."
@@ -2494,6 +2532,16 @@ be relative to that."
:group 'TeX-file
:type 'string)
+(defcustom TeX-output-dir nil
+ "The directory where the output files will be generated. The
+ directory cannot start with a `.'.
+
+If this variable is nil, AUCTeX will assume that the output
+directory is the same as the directory of TeX-master."
+ :group 'TeX-file
+ :type '(string :format "%v"))
+(put 'TeX-output-dir 'safe-local-variable 'stringp-or-null-p)
+
(defcustom TeX-style-local "style"
"Directory containing hand generated TeX information.
@@ -2502,6 +2550,12 @@ be relative to that."
:group 'TeX-file
:type 'string)
+(defun TeX--ensure-output-dir nil
+ "Checks if the output directory exists, creating it if it does not."
+ (when TeX-output-dir
+ (unless (file-exists-p TeX-output-dir)
+ (make-directory TeX-output-dir))))
+
(defun TeX-split-string (regexp string)
"Return a list of strings.
Given REGEXP the STRING is split into sections which in string was