A Weird Imagination

Compile on save

Posted in

The problem#

When developing code or creating visual artifacts in non-WYSIWYG systems, it is very useful to constantly be aware of the output of the compiler and the appearance of the artifact you are creating, whether it is a GUI, a chart, a graph, or a paper. The common way of doing this is to have an IDE specialized for the system you are using; for example, LyX provides a WYSIWYG editor for LaTeX. Similarly, there may be plugins for your text editor to support whatever kind of development you are doing. On the other hand, we can use the shell to create a solution independent of the text editor and the availability of plugins for the particular system being developed for.

Solution using sh#

The OS provides a mechanism for detecting when a file has been modified, so a script can react to that event. On Linux, this is the inotify API, but similar facilities exist on other OSes. The inotifywait command will wait until a watched file has been modified before letting the script continue. By making a simple loop, we can perform some action every time one of a set of files is modified:

while true
    latexmk -pdf "$1" </dev/null
    inotifywait -e close_write "$@"

This script takes a .tex file as the first argument and any other dependencies as further arguments and uses latexmk to recompile the .tex document any time one of those files is modified. Most PDF viewers will automatically reload the modified file, so the result is that after saving, the document preview is automatically updated within a few seconds.

The </dev/null on latexmk prevents it from blocking due to errors while still showing them on the console. The idea is to keep the focus on the text editor as much as possible; this way mistakes can be corrected without manually skipping past the errors in the console.

Solution using latexmk#

It turns out that latexmk actually has built-in support for this behavior through the -pvc (PreView Continuously) option:

latexmk -pvc -pdf "$1" </dev/null

We still need the </dev/null to skip past errors without manual intervention, but latexmk is aware of the dependencies and will watch for changes to those as well.

In order to get that to work right on my system, I had to make a ~/.latexmkrc containing

$pdf_previewer = 'start evince %O %S';

where Evince is the PDF viewer I use.


While this works pretty well for LaTeX and is adaptable to similar use cases, it has some limitations which I intend to address in future blog posts:

  1. No good way to view the output of the command. For example, it may contain useful errors or warnings. Scrolling up in the console works, but can be awkward when the boundaries between the output for multiple runs are not easy to see at a glance. One possible solution may be to use a text editor plugin for warnings and errors so the command output is not needed.

  2. We may want to run a command which does not halt and only kill it when there is a change. For example, when writing the code for a GUI, it may be useful to always have the latest version visible and ready for test interactions.

  3. Not cross-platform. As the name suggests, inotifywait uses inotify, which is Linux-only. Similar cross-platform tools exist like fswatch and watchmedo which support using kqueue on BSD and FSEvents on OS X in addition to falling back on manual polling if unable to use the OS support for watching files.

  4. Manual dependency handling. While latexmk's -pvc feature handles dependencies, the sh script has to be told what other files to watch. latexmk's -deps and -deps-out options could be used to get the list of dependencies to watch.

  5. Fixing the previous would mean tying the solution to LaTeX or latexmk. Optimally, the system would use make to be more generic across different kinds of projects.

  6. Other non-obvious details. For example, it doesn't work with sshfs.

Finally, there are existing projects that implement this functionality which I have not used. I found rerun and guard both appear to have similar goals and one of them or some other existing tool may be the right solution to these problems.


Have something to add? Post a comment by sending an email to comments@aweirdimagination.net. You may use Markdown for formatting.

There are no comments yet.