2

I want to run the following commands when emacs compiles a latex file.

FILE="paper.tex"  # currently opened buffer in the emacs
pdflatex -shell-escape -shell-escape -jobname=paper_temp $FILE;
mv paper_temp.pdf paper.pdf;
open paper.pdf;

Goal: I am using following pdf editor (https://pdfexpert.com) to read my update tex file's generated pdf in dark mode.

By default when pdflatex -shell-escape -interaction=batchmode current_buffer.tex is executed by emacs, during the compilation of the tex file,the pdf reader shows the following message with a white background for a few seconds, which hurts the eye when switching from black to white and then after compilation from white to black again.

enter image description here

So I just want to trick the pdf-reader to open the compiled pdf when emacs compiles a tex file to a different name and move it to original pdf file when it completes it operation via:

mv paper_temp.pdf paper.pdf;
open paper.pdf;

minimal.el

(require 'package)
(setq user-init-file (or load-file-name (buffer-file-name)))
(setq user-emacs-directory (file-name-directory user-init-file))

(add-to-list 'package-archives
             '("melpa" . "https://melpa.org/packages/") t)
(package-initialize)
(setq frame-background-mode 'dark)

(require 'tex)
(add-to-list 'TeX-expand-list
             '("%(mode)"
               (lambda nil
                 (if TeX-interactive-mode ""
                   " -interaction=batchmode"))))

(setq TeX-command-extra-options " -shell-escape")

(defun my-run-latex ()
  "Save all buffers and run LaTeX on the current master."
  (interactive)
  (let* ((inhibit-message t)
         (TeX-command-force "LaTeX")
         (TeX-clean-confirm t)
         (TeX-save-query nil)
         (master (TeX-master-file))
         (process (and (stringp master) (TeX-process master))))
    (TeX-save-document master)
    (when (and (processp process)
               (eq (process-status process) 'run))
      (delete-process process))
    (TeX-command-master)))

(setq LaTeX-item-indent 0)
(setq TeX-auto-save t)
(setq TeX-parse-self t)
(add-hook 'LaTeX-mode-hook 'hl-todo-mode)
(add-hook 'TeX-update-style-hook 'hl-todo-mode)
(add-hook 'LaTeX-mode-hook 'writegood-mode)
(add-hook 'LaTeX-mode-hook (lambda ()
                             (TeX-global-PDF-mode t)))

I'm using my-run-latex() function to compile my tex file.

2
  • Please clarify: You are using my-run-latex() to compile your document and are looking for a modification of this function to "trick" the pdf-reader?
    – StarBug
    Jul 3 at 20:48
  • @StarBug yes sir exactly
    – alper
    Jul 3 at 20:58

3 Answers 3

1
+50

Secret sauce is TeX-after-compilation-finished-functions.

This uses browse-url-xdg-open to open the file, so associate pdfexpert with .pdf files.


  1. Create a dummy xxx.org
  2. Export it to xxx.tex with C-c C-e l p
  3. Create a test.el file with following contents

;; FILE="paper.tex"  # currently opened buffer in the emacs
;; pdflatex -shell-escape -shell-escape -jobname=paper_temp $FILE;
;; mv paper_temp.pdf paper.pdf;
;; open paper.pdf;

(package-initialize)
(require 'package)

(require 'tex)
(add-to-list 'TeX-expand-list
             '("%(mode)"
               (lambda nil
                 (if TeX-interactive-mode ""
                   " -interaction=batchmode"))))

(defun my-run-latex ()
  "Save all buffers and run LaTeX on the current master."
  (interactive)
  (let* ((TeX-command-extra-options (format " -shell-escape -jobname=%s_temp" (TeX-master-file)))
         (inhibit-message t)
         (TeX-command-force "LaTeX")
         (TeX-clean-confirm t)
         (TeX-save-query nil)
         (master (TeX-master-file))
         (process (and (stringp master) (TeX-process master)))
         (temp-file (expand-file-name (format "%s_temp.pdf" (TeX-master-file)))))
    (TeX-save-document master)
    (when (and (processp process)
               (eq (process-status process) 'run))
      (delete-process process))
    (when (file-exists-p temp-file)
      (delete-file temp-file))
    (TeX-command-master)))

(setq LaTeX-item-indent 0)
(setq TeX-auto-save t)
(setq TeX-parse-self t)

(add-hook 'LaTeX-mode-hook (lambda ()
                             (TeX-global-PDF-mode t)))

(add-hook 'TeX-after-compilation-finished-functions
          (defun my-TeX-after-compilation-finished-functions (file-name)
            (message "compilation finished %s" file-name)
            (let ((temp-file (format "%s_temp.pdf" (file-name-sans-extension file-name))))
              (rename-file temp-file file-name t)
              (browse-url-xdg-open (browse-url-file-url file-name)))))

  1. emacs -Q. Note the use of -Q.
  2. C-x C-f ~/test.el, do M-x eval-buffer
  3. C-x C-f ~/xxx.tex
  4. M-x my-run-latex
  5. Profit!

Additional comment.

When I install the following watch for the dir where ~/xxx_temp.pdf is located

(require 'filenotify)

(defun watch-file-creation (filename)
  (message "Watching for creation of %s" filename)
  (file-notify-add-watch (file-name-directory filename)
             '(change)
             (lambda (event)
               ;; (message "event: %S" event)
               (pcase-let ((`(,descriptor ,action ,file ,file1) event))
                 (message "[%s] %s" action file)))))

(watch-file-creation (expand-file-name "~/xxx_temp.pdf"))

I get

Type ‘C-c C-l’ to display results of compilation.
[changed] /home/whitetrillium/xxx_temp.log [6 times]
[changed] /home/whitetrillium/xxx_temp.aux [2 times]
[changed] /home/whitetrillium/xxx_temp.log [2 times]
[changed] /home/whitetrillium/xxx_temp.out [2 times]
[created] /home/whitetrillium/xxx_temp.pdf [2 times]
[changed] /home/whitetrillium/xxx_temp.toc [2 times]
[changed] /home/whitetrillium/xxx_temp.pdf [2 times]
LaTeX: problems after [0] pages
compilation finished /home/whitetrillium/xxx.pdf
[changed] /home/whitetrillium/xxx_temp.aux [2 times]
[changed] /home/whitetrillium/xxx_temp.pdf [2 times]
[changed] /home/whitetrillium/xxx_temp.log [2 times]
[deleted] /home/whitetrillium/xxx_temp.pdf
[renamed] /home/whitetrillium/xxx_temp.pdf [2 times]
[created] /home/whitetrillium/xxx.pdf

which means that pdf file is getting created, and subsequently modified multiple times.

Note specifically the lines

compilation finished /home/whitetrillium/xxx.pdf
[deleted] /home/whitetrillium/xxx_temp.pdf
[renamed] /home/whitetrillium/xxx_temp.pdf [2 times]
[created] /home/whitetrillium/xxx.pdf

which summarizes what my elisp is doing, which is just what the original poster requested.


5
  • Instead of using browser to open pdf files, I was opening the pdf file on native pdf editors.I am having a error as follows: error in process sentinel: Searching for program: No such file or directory, xdg-open can we use just open unix command to open the pdf file, instead of browse-url-xdg-open?
    – alper
    Jul 12 at 12:19
  • So, don't be confused by browse in the name. It opens files with file:/// url. In my example xxx.tex is the file you are compiling and xxx_temp.pdf is the file that is passed as jobname. The call back is called only on success. So, I will be surprised the file output pdf file doesn't exist. Instead of ` (browse-url-xdg-open (browse-url-file-url file-name)` you can use (call-process "open" nil nil nil file-name). What OS are you running? xdg-open is avaiable on Linux. I have tested my change on my local machine with emacs -Q. It is unlikely that there is an error ...
    – user31220
    Jul 12 at 12:22
  • I am on macOS, ah xdg-open is not installed, seems like it runs inside xQuartz
    – alper
    Jul 12 at 12:36
  • You can use open instead. Do an M-: (call-process "open" nil 0 nil "somefile.pdf") to see if it works for you.
    – user31220
    Jul 12 at 12:38
  • (call-process "open" nil 0 nil "somefile.pdf") works! So should I do: (call-process "open" nil 0 nil filename) ?
    – alper
    Jul 12 at 12:43
1

If you use latexmk as your latex command, you can run specific commands when the compile succeeds (or not). latexmk can be used as a wrapper for various latex compilers, for example latexmk -pdflatex=xelatex -pdf %f will use xelatex to generate a pdf.

try adding something like this to the .latexmkrc file

$success_cmd = 'mv %A.pdf %A_temp.pdf && open %A_temp.pdf';

5
  • Can't it be done using pdflatex?
    – alper
    Jul 7 at 19:14
  • sure. something like latexmk -r -pdflatex=pdflatex -pdf %f
    – zzkt
    Jul 8 at 7:22
  • it gives following error: Latexmk: RC file [-pdflatex=pdflatex] does not exist
    – alper
    Jul 10 at 13:40
  • does latexmk -pdflatex -pdf %f work as expected?
    – zzkt
    Jul 11 at 11:19
  • I had to do latexmk -f -pdflatex -pdf -shell-escape file.tex this seems like works. I have tested in terminal but did not tested inside emacs tho
    – alper
    Jul 11 at 12:49
1

TeX-after-compilation-finished-functions is a variable defined in tex.el.

Its value is (my-TeX-after-compilation-finished-functions)

Hook being run after TeX/LaTeX/ConTeXt finished successfully. The functions in this hook are run with the DVI/PDF output file given as argument. Using this hook can be useful for updating the viewer automatically after re-compilation of the document.

If you use an emacs-internal viewer such as doc-view-mode or pdf-view-mode, add TeX-revert-document-buffer to this hook.

This variable may be risky if used as a file-local variable.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.