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.

Drew
  • 75,699
  • 9
  • 109
  • 225
Onner Irotsab
  • 431
  • 2
  • 9
  • https://emacs.stackexchange.com/tags/elisp/info – Drew Oct 21 '22 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 '22 at 03:48

1 Answers1

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.

NickD
  • 27,023
  • 3
  • 23
  • 42
  • @ 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! – Onner Irotsab Oct 22 '22 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 '22 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 '22 at 12:27
  • 1
    Ok, I belive I've found what does the trick: my init file loads the functions defined [here](https://lists.gnu.org/archive/html/help-gnu-emacs/2004-09/msg00350.html). With these functions loaed, all it works. Without them, I get "scan error". – Onner Irotsab Oct 22 '22 at 14:44