Hello again,

I was told that I should provide a rough sketch on what I am planning to do.

First let me discuss my current implementation for the custom output
directory (attached). The implementation was simplified a bit since my
previous email. The basic idea is to advise `TeX-active-master` to
return the build directory (from a custom variable `TeX-output-dir`)
whenever the extension is an output one (defined as matching one of
the outputs in `*TeX-clean-*-suffixes`). If `TeX-output-dir` is nil,
then `TeX-active-master` is called as usual. I also define a function
`TeX-master-output-file` that returns the value of `TeX-output-dir` of
the master-file (the variable's value of non-master files should be
irrelevant). In the attached script, I also added an example hook to
set the build directory and set `TeX-command-extra-options`
appropriately.

This works most of the time, except in cases where AUCTeX uses
`TeX-active-master` to get the master directory. For example,
`TeX-active-master` is called in `TeX-clean` without an extension and
then `file-name-directory` is called to extract the directory. In
these cases, the output directory should be used instead.

In order to implement this natively, I am planning to add the same
variable `TeX-output-dir` in AUCTeX. Then, I have two options:
1. Add a check at the beginning of `TeX-active-master` similar to the
one in my advice. If the extension is an output extension, return the
output directory instead of the master directory. I would also change
calls to TeX-active-master where a directory is needed so that an
extension is always passed (an output extension if the output
directory is needed like in `TeX-clean`, or a tex extension if not)
2. The second way to implement this is to simply replace the calls to
`TeX-active-master` in AUCTeX with calls to `TeX-master-output-file`
whenever the extension is an output one. Also, replace calls to
`TeX-active-master` in places where the output directory is needed
(like in TeX-clean).

There are a few issues that I am trying to figure out at the moment:
1. The latex compiler assumes that the output directory exists. I am
not sure where the best place to create it is.
2. I think creating an expansion variable (in `TeX-expand-list`) for
the output directory might be better than using
`TeX-command-extra-options`. This is for several reasons, most
importantly it seems that when I call `TeX-command` on a non-master
file, the local variable `TeX-command-extra-options` (from the
non-master file) is expanded rather than the one from the master file
as I would expect (As an aside, I propose that the value of the master
file be expanded instead).

Sorry for the long email, I appreciate any feedback. Especially on
which implementation is preferred.

-- Tohiko
;;; tex-output.el --- description -*- lexical-binding: t; -*-

(defcustom TeX-output-dir nil
  "*The place where the output files will be generated.

If this variable is nil, AUCTeX will assume that the output
dir is the directory of TeX-master.

It is suggested that you use the File Variables (see the info node in
the Emacs manual) to set this variable permanently for each file."
  :group 'TeX-command
  :group 'TeX-parse
  :type '(string :format "%v"))
(make-variable-buffer-local 'TeX-output-dir)
(put 'TeX-output-dir 'safe-local-variable 'stringp-or-null-p)

(defun TeX-master-output-file (&optional extension)
  "Return the value of `TeX-output-dir' in the master-file, opening it if necessary.
if the optional argument is non-nil it is appended as an extension to the output file"
  (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
        ;; Expand file name in case the master directory is different from the
        ;; current directory
        (setq name (concat (expand-file-name TeX-output-dir)
                           (TeX-master-file)))))
    (if name
        (if extension (concat name "." extension)
          name)
      (TeX-master-file extension))))

(defun TeX-clean-extensions-regexp (&optional arg)
    "Return 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"
    (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"))))))
         (regexp (concat (mapconcat 'identity suffixes "\\|")
                         "\\|" (regexp-quote (TeX-region-file t t)))))
    regexp))

(define-advice TeX-active-master
    (:around (TeX-master-file-fn &optional extension &rest args) TeX-active-master-adv)
  (if (or (null extension)
          (equal extension t)
          (not (string-match-p (TeX-clean-extensions-regexp t) (concat "." extension))))
      (apply TeX-master-file-fn (cons extension args))
    (TeX-master-output-file extension)))

;;;;;;;;;;; Example hook
(defun set-latex-build-dir ()
  ;; Check if the current file is its own master
  (setq TeX-output-dir "build/")
  (make-directory TeX-output-dir t) ;; Ensure directory exists
  (setq TeX-command-extra-options
        (concat TeX-command-extra-options " --output-directory=\"" TeX-output-dir "\"")))

(add-hook 'LaTeX-mode-hook 'set-latex-build-dir)

Reply via email to