Customizing citations depending on the author with BibLaTeX style “numeric-comp”

biberbiblatexbibliographiescitingmultiple-citations

I'd like to reproduce the results of this post using the numeric-comp citestyle. Using the solution as-is, I get an error saying "Macro 'cite' undefined", and nothing comes out boldfaced.

I tried changing cite to cite:comp in the relevant lines (see below), and got some boldface out of that, but not consistently. It looks like the last number in a compressed range does not get boldface unless it is followed by another boldface number, but I don't know why. Any help would be much appreciated. Thanks!

MWE:

\documentclass{article}
\usepackage{filecontents}
\usepackage[backend=biber,style = numeric-comp, sortcites]{biblatex}
\usepackage[colorlinks=true, breaklinks, allcolors = blue]{hyperref}
\DeclareSourcemap{%
  \maps[datatype=bibtex]{%
    \map{%
      \step[fieldsource=author, match=Doe, final]%
      \step[fieldset=keywords, fieldvalue=doe]%
    }%
  }%
}
\begin{filecontents}{\jobname.bib}
@Book{p1,
  author =       "Joe Bar",
  title =        "A Scientific Article 1",
  year =         "1995"  
}
@Book{p2,
  author =       "John Doe",
  title =        "A Scientific Article 2",
  year =         "1985"  
}
@Book{p3,
  author =       "A. U. Thor and John Doe",
  title =        "A Scientific Article 3",
  year =         "1975"  
}
@Book{p4,
  author =       "A. U. Thor and John Doe",
  title =        "A Scientific Article 4",
  year =         "2010"  
}
@Book{p5,
  author =       "Jane Zaz",
  title =        "A Scientific Article 5",
  year =         "2005"  
}
@Book{p6,
  author =       "Jane Zaz",
  title =        "A Scientific Article 6",
  year =         "2015"  
}
@Book{p7,
  author =       "Jane Zaz and John Doe",
  title =        "A Scientific Article 7",
  year =         "2020"  
}
\end{filecontents}
\addbibresource{\jobname.bib}

\DeclareFieldFormat{keywordcite}{\ifkeyword{doe}{\mkbibbold{#1}}{#1}}
\csletcs{old:cite:comp}{abx@macro@cite:comp}
\renewbibmacro{cite:comp}{\printtext[keywordcite]{\csuse{old:cite:comp}}}

\nocite{*}
\begin{document}

In \cite{p2, p3, p4, p6}, 2 and 4 should be \textbf{bold}.

In \cite{p2, p3, p4, p7}, 2, 4, and 7 should be \textbf{bold}.

In \cite{p1, p3, p4, p5, p6, p7}, 3 and 7 should be \textbf{bold}.

In \cite{p1, p2, p3}, 3 should be \textbf{bold}.

In \cite{p1, p2, p3, p7}, 3 and 7 should be \textbf{bold}.

\printbibliography
\end{document}

enter image description here

UPDATE:

I was able to make things a little better by adding the lines

\csletcs{old:cite:dump}{abx@macro@cite:dump}
\renewbibmacro{cite:dump}{\printtext[keywordcite]{\csuse{old:cite:dump}}}

enter image description here

Still not a complete solution, though.

Best Answer

Compared to other citation styles, the code of numeric-comp is incredibly complex. The different bits of the citation output are produced by different helper bibmacros and in order for the compress feature to work properly it is even necessary to print the data of certain entries "out of scope" (i.e. the citation of a certain entry may be printed when a different entry is being processed - at that time we cannot easily access other data of the entry).

This makes it pretty challenging to achieve what you want. It is not just a matter of wrapping a single bibmacro in \printtext[keywordcite], because that bibmacro may end up printing citations to other entries as well and may even not print the "current" entry at all. First we need to inject a \printtext[keywordcite]{...} in every bibmacro that produces citation output for the entry currently in scope. Then we need to "remember" the keyword status of citations that are printed "out of scope" and use this remembered status for the bibmacros that print data "out of scope". Hence we end up with the following 100-line monstrosity.

The following code was designed and tested for the current version of biblatex (v3.16 from 2020-12-31). If I recall correctly it needs at least v3.15a (2020-08-23) and will not work with older versions.

\documentclass{article}

\usepackage[backend=biber,style = numeric-comp, sortcites]{biblatex}

\usepackage[colorlinks=true, breaklinks, allcolors = blue]{hyperref}

\DeclareSourcemap{%
  \maps[datatype=bibtex]{%
    \map{%
      \step[fieldsource=author, match=Doe, final]%
      \step[fieldset=keywords, fieldvalue=doe]%
    }%
  }%
}

\makeatletter
\DeclareFieldFormat{keywordcite}{\ifkeyword{doe}{\mkbibbold{#1}}{#1}}

\newcommand*{\cbx@if@lastkeyword@doe}{}
\let\cbx@if@lastkeyword@doe\@secondoftwo

\DeclareFieldFormat{lastkeywordcite}{\cbx@if@lastkeyword@doe{\mkbibbold{#1}}{#1}}

\renewbibmacro*{cite:comp:comp}{%
  \cbx@iflabelprefixequalslast
    {\ifnumequal{\thefield{labelnumber}}{\value{cbx@tempcntb}}
       {\savefield{entrykey}{\cbx@lastkey}%
        \savefield{labelnumber}{\cbx@lastnumber}%
        \ifkeyword{doe}
          {\global\let\cbx@if@lastkeyword@doe\@firstoftwo}
          {\global\let\cbx@if@lastkeyword@doe\@secondoftwo}%
        \stepcounter{cbx@tempcnta}}
       {\ifnumequal{\thefield{labelnumber}}{\value{cbx@tempcntb}-1}
          {% current cite is *exactly* the same a previous source
           % this can only happen if the same source is cited twice
           % and sortcites is turned off
           % print nothing
          }
          {\usebibmacro{cite:comp:end}}}}
    {\usebibmacro{cite:comp:end}}%
  \setcounter{cbx@tempcntb}{\thefield{labelnumber}}%
  \savefield{labelprefix}{\cbx@lastprefix}}

\renewbibmacro*{cite:comp:inset}{%
  \stepcounter{cbx@tempcntd}%
  \ifboolexpr{    togl {cbx:subentrycomp}
              and test {\cbx@iflabelnumberandprefixequallast}}
    {\ifnumequal{\thefield{entrysetcount}}{\value{cbx@tempcntd}}
       {\savefield{entrykey}{\cbx@lastkey}%
        \savefield{entrysetcount}{\cbx@lastentrysetcount}%
        \ifkeyword{doe}
          {\global\let\cbx@if@lastkeyword@doe\@firstoftwo}
          {\global\let\cbx@if@lastkeyword@doe\@secondoftwo}%
        \stepcounter{cbx@tempcntc}}
       {\ifnumequal{\thefield{entrysetcount}}{\value{cbx@tempcntd}-1}
          {% current cite is *exactly* the same a previous source
           % this can only happen if the same source is cited twice
           % and sortcites is turned off
           % print nothing
          }
          {\usebibmacro{cite:dump:inset}%
           \ifnumgreater{\value{cbx@tempcntd}}{-1}
             {\setunit{\multicitesubentrydelim}}
             {}%
           \usebibmacro{cite:print:subentry:comp}}}}
    {\usebibmacro{cite:dump}%
     \ifnumgreater{\value{cbx@tempcntb}}{-1}
       {\multicitedelim}
       {}%
     \setcounter{cbx@tempcntd}{-1}%
     \usebibmacro{cite:print:subentry:full}%
     \savefield{labelprefix}{\cbx@lastprefix}%
     \savefield{labelnumber}{\cbx@lastnumber}}%
    \setcounter{cbx@tempcntd}{\thefield{entrysetcount}}%
    \setcounter{cbx@tempcntb}{-1}}

\renewbibmacro*{cite:print:shorthand}{%
  \printtext[bibhyperref]{%
    \printtext[keywordcite]{%
      \printfield{shorthand}}}}

\renewbibmacro*{cite:print:labelnumber}{%
  \printtext[bibhyperref]{%
    \printtext[keywordcite]{%
      \printfield{labelprefix}%
      \printfield{labelnumber}}}}

\renewbibmacro*{cite:print:subentry:comp}{%
  \printtext[bibhyperref]{%
    \printtext[keywordcite]{%
      \printfield{entrysetcount}}}}

\renewbibmacro*{cite:print:subentry:full}{%
  \printtext[bibhyperref]{%
    \printtext[keywordcite]{%
      \printfield{labelprefix}%
      \printfield{labelnumber}%
      \printfield{entrysetcount}}}}

\renewbibmacro*{cite:print:last:subentry:comp}{%
  \printtext[bibhyperref:lastkey]{%
    \printtext[lastkeywordcite]{%
      \printtext[entrysetcount]{\cbx@lastentrysetcount}}}}

\renewbibmacro*{cite:print:last:labelnumber}{%
  \printtext[bibhyperref:lastkey]{%
    \printtext[lastkeywordcite]{%
      \ifdef\cbx@lastprefix
         {\printtext[labelprefix]{\cbx@lastprefix}}
        {}%
      \printtext[labelnumber]{\cbx@lastnumber}}}}
\makeatother


\begin{filecontents}{\jobname.bib}
@Book{p1,
  author = {Joe Bar},
  title  = {A Scientific Article 1},
  year   = {1995},
}
@Book{p2,
  author = {John Doe},
  title  = {A Scientific Article 2},
  year   = {1985},
}
@Book{p3,
  author = {A. U. Thor and John Doe},
  title  = {A Scientific Article 3},
  year   = {1975},
}
@Book{p4,
  author = {A. U. Thor and John Doe},
  title  = {A Scientific Article 4},
  year   = {2010},
}
@Book{p5,
  author = {Jane Zaz},
  title  = {A Scientific Article 5},
  year   = {2005},
}
@Book{p6,
  author = {Jane Zaz},
  title  = {A Scientific Article 6},
  year   = {2015},
}
@Book{p7,
  author = {Jane Zaz and John Doe},
  title  = {A Scientific Article 7},
  year   = {2020},
}
\end{filecontents}
\addbibresource{\jobname.bib}

\begin{document}
In \cite{p2, p3, p4, p6}, 2 and 4 should be \textbf{bold}.

In \cite{p2, p3, p4, p7}, 2, 4, and 7 should be \textbf{bold}.

In \cite{p1, p3, p4, p5, p6, p7}, 3 and 7 should be \textbf{bold}.

In \cite{p1, p2, p3}, 3 should be \textbf{bold}.

In \cite{p1, p2, p3, p7}, 3 and 7 should be \textbf{bold}.

\printbibliography
\end{document}

Output is
"In [2–4, 6], 2 and 4 should be bold.
In [2–4, 7], 2, 4, and 7 should be bold.
In [1, 3–7], 3 and 7 should be bold.
In [1–3], 3 should be bold.
In [1–3, 7], 3 and 7 should be bold."
with the expected numbers in bold.

Related Question