2016-07-04 Compiling a single Beamer frame in AUCTeX

Some time ago I basically stopped using Beamer. I turned to reveal.js, and did a few presentation in it, using Org-mode’s exporter. That was nice, my slides were not “like anyone else’s” (since everyone and their mother uses Beamer), and even equations worked great thanks to MathJax.

Some time ago, I taught a Calculus course (which is a challenge on its own, probably worth a blog post or two, especially that it is not aimed at mathematicians, but geographers – but that’s another story). The slides are very diagram-heavy – you know, all sorts of stuff like tangent lines (since we’re doing derivatives), approximations of arc length or areas (since we’re doing integrals), and occasional cute pictures (since we’re also having fun, or so I hope at least).

And it turned out that reveal.js (or at least the Org reveal exporter) really doesn’t like images. And it didn’t let me zoom them. Maybe if I were a CSS wizard, I could make it play nice. But I’m not, and I started missing Beamer, with its very precise control of what goes where.

So I came back. It was kind of refreshing to play with LaTeX and TikZ again. Of course, I’m using Emacs and AUCTeX, which is really great. (It will be even better when I finally start contributing to AUCTeX. I have a few functions which make certain TeX-related editing stuff really nice – IMHO at least – and I can’t wait to incorporate them into AUCTeX. But this is again another story – and a long one, since I’m preparing a lengthy post about my issues with the FSF. OK, let’s get back on topic.)

One problem I had with Beamer is that it’s huge, and compiling a slideshow for a 90 minutes lecture (some 30 frames with 3 slides per frame on average) took a lot of time on my netbook. So here’s a tip for making the cycle faster. If you want to compile just one frame, you can press C-c . (LaTeX-mark-environment) – possibly with a prefix argument (or just press it a few times) to mark the current frame, and then press C-c C-r (TeX-command-region). The latter command is extremely useful. It takes the “pinned region” (i.e., if there’s no active region, it remembers the previously used one), saves it to a temporary file (together with the whole preamble), and launches a compile or view command on that. This way I can cut down on the compile time by at least an order of magnitude.

Of course, pressing that combo repeatedly is not something an Emacs user would do too long. Let us write a short function to do that for us.

(defun LaTeX-command-beamer-frame ()
  "Run `TeX-command-region' on the current frame environment."
  (interactive)
  (save-mark-and-excursion
    (while (not (looking-at-p "\\\\begin *{frame}"))
      (LaTeX-find-matching-begin))
    (forward-char)
    (LaTeX-mark-environment)
    (TeX-command-region)))

It is fairly simple: we climb up the document structure until we reach the beginning of a frame environment, then move forward one character so that we are actually inside it, then we mark the current environment and launch compilation on the region. In the case we are not in a frame, LaTeX-find-matching-begin throws an error, and happily save-mark-and-excursion restores the point etc. in such a case, too. (There is a little price to pay for the simplicity of the above code: the error message is a bit cryptic: Can't locate beginning of current environment. Not a huge problem in my book, so I didn’t do anything to prevent it. In case I wanted to do that, I could have wrapped the LaTeX-find-matching-begin in a condition-case.)

There is, however, another (rather annoying) issue with the above code. The point is that TeX-command-region asks the user for the command to launch. In interactive use, it’s just fine. Here, it’s a nuisance: we can safely assume that what the user wants is either just compile, or possibly DWIM (i.e., compile or launch viewer if compilation was successful and there was no need to rerun it). The cuplrit is the function TeX-command-query, which (unfortunately) does not have any switch to just return the default instead of asking the user.

There are a few solutions to this problem, none of which is simple. (I asked about it on the ML, and got a few very good responses. You can look up that thread if you want to.) Probably the easiest one is just to copy the TeX-command-region function and change what is needed. This is far from elegant, though.

A better idea might be to replace TeX-command-query with something similar that just returns the default instead of asking the user what to do. Similar in that it’s not elegant, but should work.

Probably the best idea would be just to submit a patch to AUCTeX. I’m cosidering doing exactly that, but until then I’ll resort to advising TeX-command-query. Here’s one possibility:

(defcustom TeX-command-use-default nil
  "If non-nil, just use the deafult command instead of asking.")

(defun TeX-command-query-or-default (orig-fun name)
  "A piece of advice for `TeX-command-query' to make it obey
`TeX-command-use-default'."
  (if TeX-command-use-default
      (TeX-command-default name)
    (funcall orig-fun name)))

(advice-add 'TeX-command-query :around #'TeX-command-query-or-default)

I can now let-bind the newly defined TeX-command-use-default option to t in my function:

(defun LaTeX-command-beamer-frame ()
  "Run `TeX-command-region' on the current frame environment."
  (interactive)
  (save-mark-and-excursion
    (while (not (looking-at-p "\\\\begin *{frame}"))
      (LaTeX-find-matching-begin))
    (forward-char)
    (LaTeX-mark-environment)
    (let ((TeX-command-use-default t))
      (TeX-command-region -1))))

The negative argument to TeX-command-region ensures that not only aren’t we being asked for what command to issue, but nor are we asked about e.g. which viewer to launch.

Happy TeXing!

CategoryEnglish, CategoryBlog, CategoryEmacs, CategoryLaTeX