1

I have this LaTeX code:

%% test.tex
\begin{wrapfig}
\includegraphics[width=1cm]{fig1.eps}\end{wrapfig}
\includegraphics[width=1cm]{fig2.eps}

I have a script called fix-files-ext.sh that fixes the extensions of graphic files (in this example it will change .eps to .pdf).

My script is this:

## fix-files-ext.sh
#!/usr/bin/emacs --script
emacs "$1" --batch -l ~/fix-files-ext.el ## &> /dev/null

where fix-files-ext.el contains this code:

;; fix-files-ext.el
(save-excursion
  (let* ((case-fold-search nil))
    (goto-char (point-min))
    (while (re-search-forward "\\\\includegraphics" nil t)
      (save-excursion
        (let* ((pos1 (copy-marker (progn
                                    (when (looking-at "\\(?:[ \n]+\\)?\\[")
                                      (forward-sexp))
                                    (point))))
               (pos2 (copy-marker (progn
                                    (forward-sexp)
                                    (point)))))

          (if (re-search-backward "\\.\\(e?ps\\|E?PS\\)}" pos1 t)
              (replace-match ".pdf}" t)
            (if (re-search-backward "\\.\\(JBIG2\\|JPEG\\|JP2\\|JPG\\|JPX\\|PDF\\|PNG\\)}" pos1 t)
                (replace-match (downcase (match-string 0)) t)
              (if (re-search-backward "\\.\\(tiff?\\|TIFF?\\)}" pos1 t)
                  (replace-match ".png}" t)))))))

    (save-buffer)))

Here is the output I get calling my script:

$ bash fix-files-ext.sh test.tex
Loading /etc/emacs/site-start.d/00debian.el (source)...
Loading /etc/emacs/site-start.d/50dictionaries-common.el (source)...
Loading debian-ispell...
Loading /var/cache/dictionaries-common/emacsen-ispell-default.el (source)...
Loading /var/cache/dictionaries-common/emacsen-ispell-dicts.el (source)...
Scan error: "Containing expression ends prematurely", 54, 67

The Scan error refers to the second forward-sexp. But if I open test.tex with emacs and load fix-files-ext.el with load-file, it works perfectly. Why does this happen?

Remarks

In reference to $ bash fix-files-ext.sh test.tex:

  1. If I drop \end{wrapfig}, it works.

  2. If I leave \end{wrapfig} and change the second forward-sexp to forward-list, it works.

For me it is preferable to use forward-sexp instead of forward-list because if there were unbalanced brackets in the file names of the figures, forward-list would fail unlike forward-sexp (I am a professional typesetter and sometimes it happens that the names of the figures are a bit exotic).

Beyond that, I would like to understand why the same code called first by bash and then by emacs doesn't behave the same way.

2
  • emacs.stackexchange.com/tags/elisp/info
    – Drew
    Oct 21, 2022 at 21:43
  • Try the following: start with emacs -Q, open test.tex and then M-x load-file RET fix-file-ext.el - I still get the Scan error in this case. If you are doing it in your working emacs and it succeeds, it's probably the case that your environment is different (e.g. maybe you are using AucTeX in your working emacs?)
    – NickD
    Oct 22, 2022 at 3:48

1 Answer 1

1

It is a difference between your working emacs (where you presumably load auctex - or some other package which somehow works around or hides the problem; see comments for some discussion) and a bare emacs, started with -q or --batch (Note that --batch implies -q).

If I open the file in my working emacs (where auctex is active), and do M-x load-file RET fix-file-ext.el, the file is changed and saved.

If I run emacs --batch test.tex -l ./fix-file-ext.el, then I get a Scan error.

If I run emacs -q and open test.tex and then run M-x load-file RET fix-file-ext.el I still get a scan error.

Finally, if I do a batch run but load my init file:

emacs --batch -l ~/.config/emacs/init.el test.tex -l ./fix-file-ext.el

it succeeds.

I also tried loading just auctex instead of my whole init file:

emacs --batch -l /path/to/auctex-config.el test.tex -l ./fix-file-ext.el

and that worked as well.

So for some reason (which I have not investigated), auctex changes the behavior of forward-sexp (or rather the function latex-forward-sexp which is the one used in LaTeX buffers - see the variable forward-sexp-function). That's probably a bug in the built-in tex-mode.el.

4
  • @ NickD It can't be AucTeX's fault because I don't have it installed. Anyway I tried adding my init file and now it works perfectly! Oct 22, 2022 at 10:22
  • You might want to find out exactly which part of your init file does the trick by bisecting it. In my case, I was able to get it to work with just auctex, but since I don't really know why it works with auctex, but not without it, I'd have to bisect further to pinpoint exactly what causes the behavior (or I could look at the sources and try to edebug it, since I know how to reproduce it interactively). It would be good to verify if it is indeed a bug and report it.
    – NickD
    Oct 22, 2022 at 12:25
  • And BTW, I'm not saying it is auctex's fault at all. I believe it's a bug in the latex-forward-sexp function in tex-mode.el and auctex actually does something to fix it (or at least to hide it).
    – NickD
    Oct 22, 2022 at 12:27
  • 1
    Ok, I belive I've found what does the trick: my init file loads the functions defined here. With these functions loaed, all it works. Without them, I get "scan error". Oct 22, 2022 at 14:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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