[Tex/LaTex] Emacs, AUCTeX, RefTeX and biblatex’s multicite commands

auctexbiblatexemacsreftex

I've been giving a chance to Emacs (with AUCTeX and RefTeX), but I'm still stumbling quite a lot. I've gotten the hang (and appreciated) the RefTeX way to add a citation (as described in, e.g. how to cite using emacs+auctex+reftex). Also, I'm a biblatex user, and recent versions of AUCTeX provide good support for it. However, somehow, how to make this work for biblatex multicite commands (\cites, \textcites, \parencites and so on) completely eludes me.

None of the multicite commands is available out of the box in the reftex-citation menu C-c [ (though I suppose they could be added without great difficulty). The relevant multicite commands do show up in autocompletion through C-c C-m, but then I do not get the nice regex search in the bib file (as far as I can tell. See more below, it works for regular cite commands but not for multicite).

Furthermore, syntax highlighting (fontification) only recognizes the first key of a multicite command.

Also, RefTeX's reftex-view-crossref C-c &, does not seem to work with multicite commands, returning "Not on a crossref macro argument".

Related to this, if I want to add an extra bibkey to an already existing multicite command, I also cannot access reftex facilities (with a regular cite command, placing the point before the citation command's closing brace and calling C-c [ would offer me a regex search on the bib files. This can also be used to add a citation key with a command inserted with C-c C-m).

biblatex.el does seem to include "Support for multicite commands"/"Qualified Citation Lists", but I can't find my way through it.

Am I missing something? Is there a proper "RefTeX way" to deal with biblatex's multicite commands?

In particular:

1 – What would be the normal way (that is, considering default configuration) to add one such command?

2 – How to make these commands recognized by RefTeX, so that reftex-view-crossref works and new keys can be added with RefTeX facilities after the citation command has already been inserted?

Besides that, but less important:

3 – How to add, e.g. \cites to RefTeX menu on the call to C-c [?

4 – How to make fontification work for all the keys of a multicite command?

In case someone is willing to play with the relevant settings, a MWE ("biblatex-examples.bib" should be in the same directory as the document, for things to work without further configurations):

\documentclass{article}

\usepackage[style=authoryear]{biblatex}

\addbibresource{biblatex-examples.bib}

\begin{document}

\cite{sigfridsson}

\parencites{sigfridsson}{knuth:ct}

\end{document}
%%% Local Variables:
%%% mode: latex
%%% TeX-master: t
%%% End:

[In case it is relevant, I'm using Emacs 24.5 with AUCTeX 12.1.1]

Best Answer

You have many questions here so I try to stay brief. I presume that you have these lines in your init file:

(add-hook 'LaTeX-mode-hook #'turn-on-reftex)
(setq reftex-plug-into-AUCTeX t)

1 - What would be the normal way (that is, considering default configuration) to add one such command?

RefTeX provides the variable reftex-cite-format. You can use it for custom query when you hit C-c [. With AUCTeX, you have to set LaTeX-reftex-cite-format-auto-activate to nil when setting reftex-cite-format. In your case, try:

(setq LaTeX-reftex-cite-format-auto-activate nil)

(setq reftex-cite-format
      '((?\C-m . "\\cite[][]{%l}")
        (?s    . "\\cites[][]{%l}")
        (?p    . "\\parencites[][]{%l}")
        (?P    . "\\Parencites[][]{%l}")))

in your init file. But I find the input interface in the document cumbersome: You have to do C-c [, s, go through the regex query, mark each entry and hit A. But that's a matter of taste.

2 - How to make these commands recognized by RefTeX, so that reftex-view-crossref works and new keys can be added with RefTeX facilities after the citation command has already been inserted?

This is the tricky part. You have to patch the functions reftex-figure-out-cite-format and reftex-view-crossref. Put this in your init file and restart Emacs; the original string-match lines are commented for your reference:

(with-eval-after-load "reftex-cite"
(defun reftex-figure-out-cite-format (arg &optional no-insert format-key)
  "Check if there is already a cite command at point and change cite format
in order to only add another reference in the same cite command."
  (let ((macro (car (reftex-what-macro 1)))
        (cite-format-value (reftex-get-cite-format))
        key format)
    (cond
     (no-insert
      ;; Format does not really matter because nothing will be inserted.
      (setq format "%l"))

     ((and (stringp macro)
       ;; (string-match "\\`\\\\cite\\|cite\\'" macro))
           (string-match "\\`\\\\cite\\|cite\\(?:[s*]\\|texts?\\)?\\'" macro))
      ;; We are already inside a cite macro
      (if (or (not arg) (not (listp arg)))
          (setq format
                (concat
                 (if (member (preceding-char) '(?\{ ?,))
                     ""
                   reftex-cite-key-separator)
                 "%l"
                 (if (member (following-char) '(?\} ?,))
                     ""
                   reftex-cite-key-separator)))
        (setq format "%l")))
     (t
      ;; Figure out the correct format
      (setq format
            (if (and (symbolp cite-format-value)
                     (assq cite-format-value reftex-cite-format-builtin))
                (nth 2 (assq cite-format-value reftex-cite-format-builtin))
              cite-format-value))
      (when (listp format)
        (setq key
              (or format-key
                  (reftex-select-with-char
                   "" (concat "SELECT A CITATION FORMAT\n\n"
                              (mapconcat
                               (lambda (x)
                                 (format "[%c] %s  %s" (car x)
                                         (if (> (car x) 31) " " "")
                                         (cdr x)))
                               format "\n")))))
        (if (assq key format)
            (setq format (cdr (assq key format)))
          (error "No citation format associated with key `%c'" key)))))
    format)) )

(with-eval-after-load "reftex-dcr"
(defun reftex-view-crossref (&optional arg auto-how fail-quietly)
  "View cross reference of macro at point.  Point must be on the KEY
argument.  When at a `\\ref' macro, show corresponding `\\label'
definition, also in external documents (`xr').  When on a label, show
a locations where KEY is referenced.  Subsequent calls find additional
locations.  When on a `\\cite', show the associated `\\bibitem' macro or
the BibTeX database entry.  When on a `\\bibitem', show a `\\cite' macro
which uses this KEY. When on an `\\index', show other locations marked
by the same index entry.
To define additional cross referencing items, use the option
`reftex-view-crossref-extra'.  See also `reftex-view-crossref-from-bibtex'.
With one or two C-u prefixes, enforce rescanning of the document.
With argument 2, select the window showing the cross reference.
AUTO-HOW is only for the automatic crossref display and is handed through
to the functions `reftex-view-cr-cite' and `reftex-view-cr-ref'."

  (interactive "P")
  ;; See where we are.
  (let* ((macro (car (reftex-what-macro-safe 1)))
         (key (reftex-this-word "^{}%\n\r, \t"))
         dw)

    (if (or (null macro) (reftex-in-comment))
        (or fail-quietly
            (error "Not on a crossref macro argument"))

      (setq reftex-call-back-to-this-buffer (current-buffer))

      (cond
       ;; ((string-match "\\`\\\\cite\\|cite\\*?\\'\\|bibentry" macro)
       ((string-match "\\`\\\\cite\\|cite\\(?:[s*]\\|texts?\\)?\\'\\|bibentry" macro)
        ;; A citation macro: search for bibitems or BibTeX entries
        (setq dw (reftex-view-cr-cite arg key auto-how)))
       ((string-match "\\`\\\\ref\\|ref\\(range\\)?\\*?\\'" macro)
        ;; A reference macro: search for labels
        (setq dw (reftex-view-cr-ref arg key auto-how)))
       (auto-how nil)  ;; No further action for automatic display (speed)
       ((or (equal macro "\\label")
            (member macro reftex-macros-with-labels))
        ;; A label macro: search for reference macros
        (reftex-access-scan-info arg)
        (setq dw (reftex-view-regexp-match
                  (format reftex-find-reference-format (regexp-quote key))
                  4 nil nil)))
       ((equal macro "\\bibitem")
        ;; A bibitem macro: search for citations
        (reftex-access-scan-info arg)
        (setq dw (reftex-view-regexp-match
                  (format reftex-find-citation-regexp-format (regexp-quote key))
                  4 nil nil)))
       ((member macro reftex-macros-with-index)
        (reftex-access-scan-info arg)
        (setq dw (reftex-view-regexp-match
                  (format reftex-find-index-entry-regexp-format
                          (regexp-quote key))
                  3 nil nil)))
       (t
        (reftex-access-scan-info arg)
        (catch 'exit
          (let ((list reftex-view-crossref-extra)
                entry mre action group)
            (while (setq entry (pop list))
              (setq mre (car entry)
                    action (nth 1 entry)
                    group (nth 2 entry))
              (when (string-match mre macro)
                (setq dw (reftex-view-regexp-match
                          (format action key) group nil nil))
                (throw 'exit t))))
          (error "Not on a crossref macro argument"))))
      (if (and (eq arg 2) (windowp dw)) (select-window dw))))) )

I tried this with this file and you see where it works and where not:

\documentclass{article}

\begin{filecontents}{biblatex-bib.bib}
@book{lamp:94,
  author    = {Leslie Lamport},
  title     = {LaTeX - {A} Document Preparation System: User's Guide
               and Reference Manual, Second Edition},
  publisher = {Pearson / Prentice Hall},
  year      = {1994},
  isbn      = {978-0-201-52983-8},
  timestamp = {Fri, 08 Apr 2011 18:21:00 +0200},
}

@book{mitt:97,
  author    = {Michel Goossens and
               Sebastian Rahtz and
               Frank Mittelbach},
  title     = {The LaTeX Graphics Companion - Illustrating documents
               with TeX and PostScript},
  series    = {Addison-Wesley series on tools and techniques
               for computer typesetting},
  publisher = {Addison-Wesley},
  year      = {1997},
  isbn      = {978-0-201-85469-5},
}
\end{filecontents}

\usepackage[style=authoryear]{biblatex}

\addbibresource{biblatex-bib.bib}

\begin{document}

%% =============== RefTeX standard

\cite{mitt:97}
==> \verb|C-c &| Ok, \verb|C-c [| Ok

\cites[Pre][Post]{mitt:97}[Pre][Post]{lamp:94}
==> \verb|C-c &| Ok, \verb|C-c [| Ok

\footcitetext[Pre][Post]{mitt:97}
==> \verb|C-c &| NOk, \verb|C-c [| NOk

\parencite*[Pre][Post]{mitt:97}
==> \verb|C-c &| Ok, \verb|C-c [| NOk

\parencites{mitt:97}
\parencites(GPre)()[Pre][]{mitt:97}[Pre][]{lamp:94}
\parencites(pre)()[pre][]{mitt:97}
\parencites(post)[post]{mitt:97}
==> \verb|C-c &| NOk, \verb|C-c [| NOk

%% ============== RefTeX patched

\parencites[Pre][Post]{mitt:97}[Pre][Post]{lamp:94}
==> \verb|C-c &| Ok, \verb|C-c [| Ok

\parencites(GPre)(GPost)[Pre][Post]{mitt:97}[Pre][Post]{lamp:94}
==> \verb|C-c &| NOk, \verb|C-c [| NOk

\end{document}

%%% Local Variables:
%%% mode: latex
%%% TeX-master: t
%%% End:

The patches don't work when global optional arguments in () are present. Therefore, you have to patch the function reftex-what-macro as well; but that would be beyond tex.sx. Please drop a line to bug-auctex@gnu.org. These issue should be fixed in Emacs 27.

3 - How to add, e.g. \cites to RefTeX menu on the call to C-c [?

Check point 1.

4 - How to make fontification work for all the keys of a multicite command?

I'm afraid this is a "won't fix". Fontification is done by font-latex.el shipped with AUCTeX which in general can only fontify fixed number of arguments.