1

I'd like to have a function that asks for a number n and executes the default compile command n-times afterwards. That is to say unlike C-c C-c (i.e. TeX-command-master) I don't want to be asked which command to run, it should select the default compile command based on the AUCTeX settings. Naturally if any error occurs the execution should stop.

I know about TeX-texify, however, this doesn't statisfy my needs because sometimes I just want emacs to run pdflatex five times indepent of what the AUCTeX parser thinks is adequate.

Any help is much appreciated!


Edit: I have looked into this a little further and using code from the above reference I have started writing a function that does this. However, it has one major flaw. Let me first give you the code:

(defcustom TeX-MultiTeX-Command "LaTeX" "Default MultiTeX command" :type 'string :group 'TeX-command)
(defun TeX-MultiTeX (n)
  "Run TeX-command n-times"
  (interactive "nRun TeX/LaTeX how many times: ")
  (while (> n 0)
      (TeX-command TeX-MultiTeX-Command 'TeX-master-file)
    (setq n (- n 1))))

As you can see, I have implemented a config variable for selecting the correct compilation command. Now let me present the problem:

The compilation of the LaTeX document takes some time, however, my function instantly calls the second (and following) executions of the compile command. Maybe someone can provide help in finding a solution that checks whether compilation has finished successfully prior to executing (TeX-command TeX-MultiTeX-Command 'TeX-master-file), then executes said function or prints some error message if compilation finished with an error.

elemakil
  • 3,681
  • 28
  • 53

2 Answers2

2

It seems that you need a synchronous way to run TeX-command. I haven't word with TeX-command, but if it uses the compilation API, it can be made to wait for the compilation to finish, although it's not exactly obvious how to do that. Here is an example that uses compilation-finish-functions to achieve the desired effect:

(require 'cl)  ; for lexical-let

(defun compile-and-wait (compilefun)
  (interactive)
  (lexical-let ((done nil) finish-callback)
    (setq finish-callback
          ;; when the compilation is done, remove the callback from
          ;; compilation-finish-functions and interrupt the wait
          (lambda (buf msg)
            (setq compilation-finish-functions
                  (delq finish-callback compilation-finish-functions))
            (setq done t)))
    (push finish-callback compilation-finish-functions)
    (funcall compilefun)
    (while (not done)
      (sleep-for .1))))

EDIT
AUC TeX is not using compilation mode to spawn TeX, so the above cannot work. Since it's still useful for other compilation buffers, I'm leaving it in the answer. Another way to implement TeX-MultiTeX is by binding TeX-process-asynchronous to nil, which should ensure that AUC TeX waits for the command to finish.

user4815162342
  • 141,790
  • 18
  • 296
  • 355
  • This is not working as expected. The first compile is spawned, however, after compilation finished the loop variable decrement is not reached (I've added debug output before and after the `compile-and-wait` call and the post-output is not reached). When I give some input (scroll mouse, press button, etc.) the next **and** next-to-next compilation processes are spawned i.e. once again two compilation processes are executed at the same time. This continues until only one process is running (and then none of course). – elemakil May 23 '13 at 18:28
  • @elemakil I fixed the problem that input interrupts `sit-for`, but it turns out that AUX TeX doesn't use compilation mode at all, so that approach cannot work. Fortunately, binding `TeX-process-asynchronous` works in my (simple) tests, so I've updated the answer to use that instead. – user4815162342 May 23 '13 at 19:05
  • Thanks anyways! I agree with you and think this might be of use for some other usecase. In the meantime I have developed a different solution with the help of the code of the `TeX-texify` function which I linked in my question. I have posted this as solution, maybe you want to have a look at it and give some comments on improvements? I'm more or less copy and pasting code from `TeX-texify` without fully understanding what each piece does... – elemakil May 23 '13 at 19:07
  • @elemakil Have you read the updated version of my answer? You should at least try the solution I propose because it is based on your previous code, and trivial to understand. Just ignore `compile-and-wait`, it's only left for reference. – user4815162342 May 23 '13 at 19:09
  • There's no error, however after the first compilation finishes the compilation command is not re-executed. The loop is iterated but `AUCTeX`'s compilation routine is not called (I think; this assumption is based on the fact that the status output from AUCTeX is missing and compilation finishes by far too fast to be actually executed). – elemakil May 23 '13 at 19:15
  • @elemakil OK, thanks for checking it out. I've now removed the faulty code from the answer and only left `compile-and-wait` (which works nicely for compilation buffers) in case someone needs it later. – user4815162342 May 23 '13 at 19:39
2

With the help of the code of the TeX-texify function I have developed a function that does what I want, the code is given below.

I'd like to thank user4815162342; although this solution is not based on his suggestion, I think his solution might be of use for a different problem. Also I'd like to thank TN, the author of TeX-texify, I shamelessly took and adapted his code for my problem. ;)

(defcustom TeX-MultiTeX-Command "LaTeX"
  "Default MultiTeX command"
  :type 'string :group 'TeX-command)

(defun TeX-MultiTeX-sentinel (&optional proc sentinel)
  "Non-interactive! Call the standard-sentinel of the current LaTeX-process.
If there is still something left do do start the next latex-command."
  (set-buffer (process-buffer proc))
  (funcall TeX-MultiTeX-sentinel proc sentinel)
  (let ((case-fold-search nil))
    (when (string-match "\\(finished\\|exited\\)" sentinel)
      (set-buffer TeX-command-buffer)
      (unless (plist-get TeX-error-report-switches (intern (TeX-master-file)))
        (TeX-MultiTeX TeX-MultiTeX-num-left)))))

(defun TeX-MultiTeX (n)
  "Run TeX-command n-times"
  (interactive "nRun TeX/LaTeX how many times: ")
  (when (or (called-interactively-p 'any)
        (null (boundp 'TeX-MultiTeX-num-left)))
    (setq TeX-MultiTeX-num-left n))
  (if (>= TeX-MultiTeX-num-left 1)
      (progn
    (TeX-command TeX-MultiTeX-Command 'TeX-master-file)
    (setq TeX-MultiTeX-num-left (- TeX-MultiTeX-num-left 1))
    (setq proc (get-buffer-process (current-buffer)))
    (setq TeX-MultiTeX-sentinel (process-sentinel proc))
    (set-process-sentinel proc 'TeX-MultiTeX-sentinel))))
elemakil
  • 3,681
  • 28
  • 53
  • Works (with a little tweak) for other functions -- e.g., automatically display the pdf file upon completion of a successful build. Thank you for sharing this code with the community. – lawlist Oct 14 '13 at 22:15