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

Reply via email to