As you might have noticed, I hardly ever write about TeX anymore. This is because I use it much less these days – apart from my work for Wiadomości Matematyczne (which will end in a few weeks, too) I don’t really need it that much anymore. (Well, I will use it from time to time, of course, for larger writing projects, and there are a few of them on the horizon.)
A few days ago, however, I needed to do something I consider really blogworthy, even though the tip I’m going to share today is (surprise, surprise!) very Emacs-centric.
I was editing a paper which used italics (with the \emph
LaTeX macro) really a lot (more than 100 times). Very many (but not all) of its occurrences were to be changed to quotes, so that e.g. \emph{petrichor}
should be changed to ,,petrichor’’
etc.
I could do that with query-replace-regexp
, of course, assuming that there were no braces within the italic text. As we know, regular expressions are not the right tool if we want to do delimiter pairing. Hence I decided to go another route and use keyboard macros – Emacs has the very useful forward-sexp
(and backward-sexp
) commands which take nested delimiters into account.
So, I first wanted to have a sequence of keystrokes that would find the next occurrence of \emph
and wait for my input. This is easy enough, so I just needed to record the sequence C-s \emph RET C-x
q
. When playing the macro back, Emacs would stop there and let me press SPC
or y
to continue or DEL
or n
to skip the rest of the macro (which is a lot like query-replace
). If I want to do the replacing in this particular place, there is one minor gotcha: I can’t replace the opening brace with the opening quote, since then forward-sexp
won’t have the correct “starting point”. This means that I want to somehow “store” the position of the opening brace, jump (with forward-sexp
) to the closing one, change it into a closing quote, jump back (without backward-sexp
, which wouldn’t work now as there is no closing brace anymore) and change the opening brace into an opening quote. Fortunately, Emacs has exactly what I need to store a position in the buffer and jump back to it – the mark. So, here is another sequence of keystrokes to add to my macro:
M-DEL ;; kill the "emph" DEL ;; delete the backslash 2*C-SPC ;; set mark and deactivate mark (no need for region!) M-C-f ;; move to the closing brace... DEL ;; ...and delete it 2*' ;; type the closing quote C-u C-SPC ;; go back to the opening brace... C-d ;; ...and delete it 2*, ;; type the closing brace
and that’s it, I finished it with <f4>
. Notice that I used double C-SPC
so that the region doesn’t get activated – this wasn’t really necessary, single C-SPC
would do, too.
And now replacing the italics with quotes is easy: just press <f4>
and then y
or n
, then <f4>
again etc.
But wait, that’s not all! I streamlined this process even more. Emacs keyboard macros have this very useful feature where you can tell Emacs to play a macro several times by giving a prefix argument to <f4>
. And since recording a macro which finds (e.g. using C-s
) a place in the buffer, operates on it somehow and then moves on to the next occurrence is quite a common use-case, you can also give a prefix argument of zero to repeat the macro indefinitely until Emacs beeps (more or less, i.e., until you get an error or press C-g
). So, I could now say C-u 0 <f4>
and just press y
or n
repeatedly until I got to the last occurrence when Emacs would beep at me and break out of the macro loop.
Well, of course all this can be done in a different way. One other solution to my problem would be to use multiple cursors – although this one has a drawback in that not all instances of the changed string would be visible at once, and editing things I don’t see is something I really don’t like. I could have used query-replace-regexp
anyway, since it just so happened that I didn’t have any braces within my \emph
macros. If I knew I wanted to replace all instances, I could use Iedit. Finally, I could define a one-parameter TeX macro \quote
putting its parameter in quotes and just query-replace
the string \emph
with \quote
, keeping the parameter (with or eithout braces) intact. But I figured that the trick with keyboard macros, even if not the simplest one, is worth sharing – especially that it can be used with things other than simple replacement, like changing the lettercase etc.
CategoryEnglish, CategoryBlog, CategoryEmacs, CategoryTeX, CategoryLaTeX