0

After inspecting this question and the unaccepted answer, I tried to test it. First I tested the recommended command with:

fswatch -o report.tex | xargs -n1 -I{} pdflatex report.tex

Which led to an infinite compilation loop, which I consider slightly inefficient, and furthermore, it does not create a long enough window-of-opportunity in which the PDF is accessible. So I tried to debug why fswatch yields an infinite compilation loop using a ctrl+s command in TexMaker in the report.tex file:

fswatch -o report.tex | xargs -n1 -I{} echo "hello world"
hello world
hello world

There I observed the ctrl+s/saving of the report.tex triggers two detected changes by fswatch. Furthermore, I tested it on a f6 command in TexMaker, as well as on the pdflatex report.tex command, and observed fswatch detected 3 changes for both attempts:

fswatch -o report.tex | xargs -n1 -I{} echo "hello world"
hello world
hello world
hello world

The latter seems to be sufficient to cause the infinite compilation loop. Hence, I would like to ask, how can I ensure the report.tex is compiled once when a change is saved to it from TexMaker?

I think subquestions that may lead to a working answer may be as listed below, yet I did not find a satisfying answer to these:

  • Does for example the fswatch have an argument to ignore changes for n-miliseconds or for the next n-changes? It appears to me that section 3.2.3 Numeric Event Flags of the fswatch documentation seems to allow for only using the n-th event flag. Yet I did not yet successfully implement passing such an argument to inhibit compilation.
  • Or are there arguments I could pass to the pdflatex report to reduce the three detected changes upon compilation to the report.tex to zero changes?
  • Does TexMaker have an option to reduce the amount of changes to the report.tex from two to one upon saving with ctrl+s?
a.t.
  • 103

1 Answers1

2

fswatch uses various backends depending on various OS. Let's assume the overall behavior is the same.

On my Linux system, attempts with fswatch (and option -x) give PlatformSpecific events which doesn't help to distinguish between a read event, a write event, an open event and a close event among many other possible events (note that Linux' inotify even distinguishes between two type of close events, one after no change, and one after changes, which would help further here). That's also why you get multiple events.

Reading from the source will trigger a compilation attempt, which will among other things read again this source. Loop created.

That's the cause of all your problems. You should trigger only on write events and also only once the file stops being written to, but fswatch considers all these events to be all PlatformSpecific. You need (a) tool(s) that can distinguish between the events, or else do periodic polls that compare dates or contents (I believe the last part is what is doing the accepted answer from OP's link).

You could use fswatch in --one-event mode without xargs combined with OP's linked accepted answer so fswatch doesn't get triggered again indefinitely but waits for pdftex to finish.. Of course you have to deal with race conditions when doing so in case you miss an event between.

As a conclusion: don't try to adapt everything to fswatch, change fswatch with a more adequate tool.


Example of alternate method on Linux (As this is specific OS related and OP didn't state an OS I'm going with this example).

inotifywait has the right options to monitor writes, and actual only end-of-write (so not MODIFY event, but only CLOSE_WRITE event). There might maybe be other things to check and adapt to when the file is actually moved, deleted and replaced, but I'm not attempting to figure out all the details. So:

inotifywait -m -e CLOSE_WRITE report.tex | xargs -n1 -I{} pdflatex report.tex

would be a good start.

To feed an event loop:

inotifywait -m -r -e CLOSE_WRITE somedir | while read -r dir events filename; do
    if [ "$filename" != "${filename%.tex}" ]; then
        pdflatex "$dir/$filename"
    fi
done

could be a good start. Except...

Alas there are certainly caveats, starting with filenames including spaces or special characters. They could be further addressed for example with --format which appears to accept \0 in the output (I don't think --csv is enough), but then the shell can't cope with this in a read loop. Sooner or later a non-shell tool using the inotify facility but not the inotifywait command would be better suited (eg: https://pypi.org/project/inotify/).

A.B
  • 36,364
  • 2
  • 73
  • 118
  • Thank you for your detailed answer! I verified your suggestion and noticed it also works on directories that only contained .tex and .png files: inotifywait -m -e CLOSE_WRITE report.tex \ Chapters/* \ Appendices/* \ Images/* \ | xargs -n1 -I{} ./compile_script.sh where every \\ is followed by a new line. – a.t. May 16 '21 at 12:56
  • 1
    The second (the event loop) checks the event is about a *.tex file. Anyway, again, the CLI tool's output isn't optimal to handle special characters in filenames. – A.B May 16 '21 at 13:28
  • +1. also, you can use a Makefile to "compile" a pdf from its TeX source code if it has changed. Run "make report.pdf" with a make rule saying that "report.pdf" depends on "report.tex" (and whatever else it needs) and can be built by running "pdflatex report.tex" – cas May 17 '21 at 02:17